【解题报告】 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 }