ZJOI2009 狼和羊的故事

来源:互联网 发布:c语言 if语句 字符串 编辑:程序博客网 时间:2024/04/29 08:13

题目大意

“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” 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%的数据 nm3
30%的数据 nm20
100%的数据 nm100

思路分析

这道题目不难想到是一道最小割的题。我们要使得羊和狼不存在路,就可以转换为羊集和狼集不从在通路,那么这样就转换成了一个最小割的题目了。

连边方法

(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 100000000using 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;}
0 0