题目描述
“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。
输入
文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。
输出
文件中仅包含一个整数ans,代表篱笆的最短长度。
因为每块领地都是正方形格子,我们把相邻格子连起来,再沿着格子边缘画篱笆,可以发现:篱笆恰好把连的边割开了,这道题其实就是求最小割!把问题转换成求最大流就行了,将狼从源点连过来,将羊连向汇点。那么0怎么办?如果把它划分给狼或者羊,一定会有更优的解,那就直接把0放在狼和羊中间,这样就是S——>狼——>0——>羊——>T。然后直接跑最大流即可。
最后附上代码。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 int next[1000001]; 9 int to[1000001]; 10 int val[1000001]; 11 int head[1000001]; 12 int tot=1; 13 int q[1000001]; 14 int s[120][120]; 15 int n,m; 16 int S,T; 17 int ans; 18 int d[1000001]; 19 const int INF=0x3f3f3f3f; 20 void add(int x,int y,int v) 21 { 22 tot++; 23 next[tot]=head[x]; 24 head[x]=tot; 25 to[tot]=y; 26 val[tot]=v; 27 tot++; 28 next[tot]=head[y]; 29 head[y]=tot; 30 to[tot]=x; 31 val[tot]=0; 32 } 33 bool bfs(int S,int T) 34 { 35 int r=0; 36 int l=0; 37 memset(d,-1,sizeof(d)); 38 q[r++]=S; 39 d[S]=0; 40 while(l<r) 41 { 42 int now=q[l]; 43 for(int i=head[now];i;i=next[i]) 44 { 45 if(d[to[i]]==-1&&val[i]!=0) 46 { 47 d[to[i]]=d[now]+1; 48 q[r++]=to[i]; 49 } 50 } 51 l++; 52 } 53 if(d[T]==-1) 54 { 55 return false; 56 } 57 else 58 { 59 return true; 60 } 61 } 62 int dfs(int x,int flow) 63 { 64 if(x==T) 65 { 66 return flow; 67 } 68 int now_flow; 69 int used=0; 70 for(int i=head[x];i;i=next[i]) 71 { 72 if(d[to[i]]==d[x]+1&&val[i]!=0) 73 { 74 now_flow=dfs(to[i],min(flow-used,val[i])); 75 val[i]-=now_flow; 76 val[i^1]+=now_flow; 77 used+=now_flow; 78 if(now_flow==flow) 79 { 80 return flow; 81 } 82 } 83 } 84 if(used==0) 85 { 86 d[x]=-1; 87 } 88 return used; 89 } 90 void dinic() 91 { 92 while(bfs(S,T)==true) 93 { 94 ans+=dfs(S,INF); 95 } 96 } 97 int main() 98 { 99 scanf("%d%d",&n,&m); 100 S=n*m+1; 101 T=n*m+2; 102 for(int i=1;i<=n;i++) 103 { 104 for(int j=1;j<=m;j++) 105 { 106 scanf("%d",&s[i][j]); 107 if(s[i][j]==2) 108 { 109 add(m*(i-1)+j,T,INF); 110 } 111 else if(s[i][j]==1) 112 { 113 add(S,m*(i-1)+j,INF); 114 } 115 } 116 } 117 for(int i=1;i<=n;i++) 118 { 119 for(int j=1;j<=m;j++) 120 { 121 int x=(i-1)*m+j; 122 if(s[i][j]==1||s[i][j]==0) 123 { 124 if(i-1>=1&&(s[i-1][j]==2||s[i-1][j]==0)) 125 { 126 add(x,m*(i-2)+j,1); 127 } 128 if(j-1>=1&&(s[i][j-1]==2||s[i][j-1]==0)) 129 { 130 add(x,m*(i-1)+j-1,1); 131 } 132 if(i+1<=n&&(s[i+1][j]==2||s[i+1][j]==0)) 133 { 134 add(x,m*i+j,1); 135 } 136 if(j+1<=m&&(s[i][j+1]==2||s[i][j+1]==0)) 137 { 138 add(x,m*(i-1)+j+1,1); 139 } 140 141 } 142 } 143 } 144 dinic(); 145 printf("%d",ans); 146 return 0; 147 }