1. 程式人生 > >【解題報告】 Leapin' Lizards HDU 2732 網路流

【解題報告】 Leapin' Lizards HDU 2732 網路流

【解題報告】 Leapin' Lizards HDU 2732 網路流

題外話


  在正式講這個題目之前我想先說幾件事
  1. 如果大家要做網路流的題目,我在網上看到一個傢伙,他那裡列出了一堆網路流的題目,而且還給他們分門別類,並且標註了難度,感覺挺好的,網址是[夏天的風](https://blog.csdn.net/shahdza/article/details/7779537)
  2. 這道題有個坑點!!!!


正題


  首先,當然是直接貼上[題目](http://acm.hdu.edu.cn/showproblem.php?pid=2732)的連結,題號是2732。
  然後接下來是CSDN的連結(https://blog.csdn.net/Liang_Si_FFF/article/details/84992526)。


題目大意


* 現在給你一個n*m的矩陣,每一個點表示一根柱子,柱子之間沒有道路。


* 在某些柱子上面,會有蜥蜴,(每一個柱子上面最多一個蜥蜴),現在他們被困在那裡了。但是每個蜥蜴都可以跳,跳的距離為d,所以只要兩根柱子的距離不超過d,他們就可以跳到相鄰的柱子上面。如果一個蜥蜴可以跳出矩陣外面,那麼它就得救了。坑點來了!不知道是我題目沒有看清楚的緣故,還是題目沒有明說的緣故,這裡的距離指的是曼哈頓距離。要不是我看了別人的題解,我還會一直困在樣例資料呢


* 但是,每一根柱子的質量都不是很好,都有一個壽命值(整數)。每當有一個蜥蜴從這跟柱子起跳,這跟柱子的壽命值就會減一,減到0之後柱子就斷了。(只有起跳的時候會減,如果有一個蜥蜴跳到這上面,是不會有事的)


* 現在問你,不能獲救的蜥蜴最少是多少了?


* 坑點二:輸出資料的時候,不僅要注意有和沒有,而且還要注意單複數。不過還好,我一開始就注意到了。比如下面:

 

Case #1: 2 lizards were left behind.
Case #2: no lizard was left behind.
Case #3: 3 lizards were left behind.
Case #4: 1 lizard was left behind.


構圖方法


1. 拆點,將每一個點拆成兩個點,分別叫做start和end,start,然後再start之間連一條容量為壽命值的邊,表示這個柱子最多隻能跳幾次。


2. 如果一個蜥蜴可以從柱子u跳到柱子v上面,則從u~end~連一條邊到v~start~,(容量隨意,只要大於u的壽命值就行)表示蜥蜴能夠從這個柱子跳到另一個柱子。


3. 如果一個蜥蜴能夠從柱子u跳出這個矩陣,那麼就從u~end~連一條邊到匯點T(同樣容量隨意,只要大於u的壽命值就行)


4. 如果某一個柱子u上面在初始狀態下是有蜥蜴的,那麼從頭源點S連一條邊到u~start~,容量為1,表示這個柱子上面只有一個蜥蜴(畢竟題目裡面說了嘛,每根柱子上面最多隻有一個蜥蜴)


5. 這個圖的最大流就是能夠逃出去的蜥蜴的數量。所以提前算出有多少了蜥蜴之後,減去最大流,就是不能獲救的蜥蜴的個數。


AC程式碼

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 using namespace std;
  5 const int INF=100000000;
  6 const int N=1000;
  7 const int M=N*N;
  8 int Head[N],Next[M],Ver[M],Edge[M],tot=1;//利用前向星儲存
  9 int D[N];//dinic演算法需要用到的深度值
 10 int map[30][30];//用來存每一個柱子的壽命值
 11 int mark[30][30];//給每一個柱子標號
 12 int S=401,T=402;
 13 char temp[30];//由於題目用字串輸入,所以弄一個字元陣列
 14 void add(int,int,int);//連邊函式
 15 bool bfs(void);//dinic演算法數深度函式
 16 int dinic(int,int);//就是dinic
 17 int min(int,int);
 18 int max(int,int);
 19 int abs(int);
 20 int main()
 21 {
 22     int Case;
 23     scanf("%d",&Case);//總共要Case組資料
 24     for(int cnt=1;cnt<=Case;cnt++)
 25     {
 26         memset(Head,0,sizeof(Head));
 27         int n,d,m=0;
 28         scanf("%d%d",&n,&d);
 29         getchar();
 30         for(int i=1;i<=n;i++)
 31         {
 32             fgets(temp,30,stdin);
 33             if(!m) m=strlen(temp)-1;
 34             for(int j=1;j<=m;j++)
 35                 map[i][j]=temp[j-1]-'0';
 36         }
 37         int k=1;
 38         for(int i=1;i<=n;i++)
 39             for(int j=1;j<=m;j++)
 40                 mark[i][j]=k++;//這個地方就是給每一根柱子都標一個號
 41                 //然後就用這個號碼來標註柱子u的u_start,用u_start+T表示
 42                 //u_end
 43         for(int i=1;i<=n;i++)
 44             for(int j=1;j<=m;j++)
 45             {
 46                 if(map[i][j])
 47                 {
 48                     add(mark[i][j],mark[i][j]+T,map[i][j]);
 49                     if(i-d<1||i+d>n||j-d<1||j+d>m)
 50                         add(mark[i][j]+T,T,map[i][j]);
 51                     int L=min(m,j+d),U=min(n,i+d);
 52                     for(int I=max(1,i-d);I<=U;I++)
 53                         for(int J=max(1,j-d);J<=L;J++)
 54                             if(map[I][J]&&(I!=i||J!=j)&&(abs(I-i)+abs(J-j)<=d))
 55                                 add(mark[i][j]+T,mark[I][J],map[i][j]);
 56                                 
 57                 }
 58             }
 59         int sum=0;
 60         for(int i=1;i<=n;i++)
 61         {
 62             fgets(temp,30,stdin);
 63             for(int j=1;j<=m;j++)
 64                 if(temp[j-1]=='L')
 65                 {
 66                     add(S,mark[i][j],1);
 67                     sum++;
 68                 }
 69         }
 70         int max_flow=0;
 71         while(bfs()) max_flow+=dinic(S,INF);
 72         int left=sum-max_flow;
 73         if(left==0)
 74             printf("Case #%d: no lizard was left behind.\n",cnt);
 75         else if(left==1)
 76             printf("Case #%d: 1 lizard was left behind.\n",cnt);
 77         else printf("Case #%d: %d lizards were left behind.\n",cnt,left);
 78     }
 79     return 0;
 80 }
 81 int dinic(int x,int flow)
 82 {
 83     if(x==T) return flow;
 84     int rest=flow;
 85     for(int p=Head[x];rest&&p;p=Next[p])
 86     {
 87         if(D[Ver[p]]==D[x]+1&&Edge[p])
 88         {
 89             int k=dinic(Ver[p],min(rest,Edge[p]));
 90             if(!k) D[Ver[p]]=0;
 91             Edge[p]-=k;
 92             Edge[p^1]+=k;
 93             rest-=k;
 94         }
 95     }
 96     return flow-rest;
 97 }
 98 bool bfs(void)
 99 {
100     memset(D,0,sizeof(D));
101     queue <int> q;
102     q.push(S);
103     D[S]=1;
104     while(!q.empty())
105     {
106         int x=q.front();
107         q.pop();
108         for(int p=Head[x];p;p=Next[p])
109             if(!D[Ver[p]]&&Edge[p])
110             {
111                 D[Ver[p]]=D[x]+1;
112                 if(Ver[p]==T) return 1;
113                 q.push(Ver[p]);
114             }
115     }
116     return 0;
117 }
118 void add(int u,int v,int c)
119 {
120     Next[++tot]=Head[u],Head[u]=tot,Edge[tot]=c,Ver[tot]=v;
121     Next[++tot]=Head[v],Head[v]=tot,Edge[tot]=0,Ver[tot]=u;
122 }
123 inline int min(int a,int b)
124 {
125     return a<b?a:b;
126 }
127 inline int max(int a,int b)
128 {
129     return a>b?a:b;
130 }
131 inline int abs(int x)
132 {
133     return x<0?-x:x;
134 }