题目大意
“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。
Input
文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。
Output
文件中仅包含一个整数ans,代表篱笆的最短长度。
Sample Input
2 2
2 2
1 1
Sample Output
2
数据范围
10%的数据
n,m≤3
30%的数据
n,m≤20
100%的数据
n,m≤100
思路分析
这道题目不难想到是一道最小割的题。我们要使得羊和狼不存在路,就可以转换为羊集和狼集不从在通路,那么这样就转换成了一个最小割的题目了。
连边方法
(S→狼,∞) , (狼→相邻的草或羊,1) , (草→相邻的草或羊,1) , (羊→T,∞) .
参考代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define maxn 105
#define oo 100000000
using namespace std;
const int fx[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
int a[maxn*maxn],head[maxn*maxn],t[maxn*maxn*10],next[maxn*maxn*10],v[maxn*maxn*10],sum;
int n,m;
int vh[maxn*maxn],pre[maxn*maxn],his[maxn*maxn],di[maxn*maxn],dis[maxn*maxn];
void insert(int x,int y,int z){
t[++sum]=y;
v[sum]=z;
next[sum]=head[x];
head[x]=sum;
}
int main(){
scanf("%d%d",&n,&m);
fo(i,1,n*m) scanf("%d",&a[i]);
sum=1;
fo(i,1,n)
fo(j,1,m){
int w=(i-1)*m+j;
if (a[w]==1){
insert(0,w,oo);
insert(w,0,0);
fo(k,0,3){
int xx=i+fx[k][0],yy=j+fx[k][1];
if (xx<=0||yy<=0||xx>n||yy>m||a[(xx-1)*m+yy]==1) continue;
insert(w,(xx-1)*m+yy,1);
insert((xx-1)*m+yy,w,0);
}
}
else if (a[w]==0){
fo(k,0,3){
int xx=i+fx[k][0],yy=j+fx[k][1];
if (xx<=0||yy<=0||xx>n||yy>m||a[(xx-1)*m+yy]==1) continue;
insert(w,(xx-1)*m+yy,1);
insert((xx-1)*m+yy,w,0);
}
}
else {
insert(w,n*m+1,oo);
insert(n*m+1,w,0);
}
}
bool p;
int tot=n*m+2,x=0,aug=oo,ans=0;
vh[0]=tot;
while (dis[0]<tot){
p=0;
his[x]=aug;
for(int tmp=di[x];tmp;tmp=next[tmp]){
if (v[tmp]&&dis[t[tmp]]+1==dis[x]){
p=1;
di[x]=tmp;
pre[t[tmp]]=x;
aug=min(aug,v[tmp]);
x=t[tmp];
if (x==n*m+1){
ans+=aug;
while (x) {
int last=pre[x];
v[di[last]]-=aug;
v[di[last] ^ 1]+=aug;
x=last;
}
}
break;
}
}
if (p) continue;
int k,min=tot;
for(int tmp=head[x];tmp;tmp=next[tmp])
if (dis[t[tmp]]<min&&v[tmp]) min=dis[t[tmp]],k=tmp;
if (--vh[dis[x]]==0) break;
vh[++min]++;
dis[x]=min;
di[x]=k;
if (x){
x=pre[x];
aug=his[x];
}
}
printf("%d\n",ans);
return 0;
}