ZJOI2009——狼和羊的故事(最小割最大流定理)

来源:互联网 发布:同花顺软件手机版 编辑:程序博客网 时间:2024/05/18 00:33
1412: [ZJOI2009]狼和羊的故事

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 732  Solved: 406
[Submit][Status][Discuss]
Description
“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” 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

解析:

          很容易看出是最小割。。。因为要将狼和羊分开

          狼连原点,边权inf,羊连汇点,边权inf。。。

          中间,狼到空地,狼到羊,空地到羊,连边,边权为1.。。。

代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define inf 1000000000const int dx[4]={0,1,0,-1};const int dy[4]={1,0,-1,0};int n,m,s,t,map[110][110],l=0;struct node{    int u,v,c,next;}edge[100000];int head[100000];int d[10010],sumd[10010];void read(){    freopen("wolf.in","r",stdin);    freopen("wolf.out","w",stdout);}void add(int u,int v,int c){  //  printf("%d %d %d\n",u,v,c);    edge[l].u=u;    edge[l].v=v;    edge[l].c=c;    edge[l].next=head[u];    head[u]=l++;    edge[l].u=v;    edge[l].v=u;    edge[l].c=0;    edge[l].next=head[v];    head[v]=l++;}int sap(int u,int flow){    if(u==t)return flow;    int sum=0;    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].v;        if(edge[i].c && d[u]==d[v]+1)        {            int t=sap(v,min(edge[i].c,flow-sum));            sum+=t;            edge[i].c-=t;edge[i^1].c+=t;            if(sum==flow)return sum;            if(d[0]>=t)return sum;        }    }    sumd[d[u]]--;    if(sumd[d[u]]==0)d[0]=t+1;    ++sumd[++d[u]];    return sum;}bool check(int x,int y){    if(1<=x&&x<=n&&y>=1&&y<=m)return 1; else return 0;}void work(){    scanf("%d%d",&n,&m);    s=0;t=n*m+1;    memset(head,-1,sizeof(head));    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)            scanf("%d",&map[i][j]);    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)        {            int cnt=(i-1)*m+j;            if(map[i][j]==1)            {                add(s,cnt,inf);                for(int k=0;k<4;k++)                {                    int newx=i+dx[k];                    int newy=j+dy[k];                    if(check(newx,newy))                    {                        int nuk=(newx-1)*m+newy;                        if(map[newx][newy]!=1)add(cnt,nuk,1);                    }                }            }            if(map[i][j]==2)add(cnt,t,inf);            if(map[i][j]==0)            {                for(int k=0;k<4;k++)                {                    int newx=i+dx[k];                    int newy=j+dy[k];                    if(check(newx,newy))                    {                        int nuk=(newx-1)*m+newy;                        if(map[newx][newy]!=1)add(cnt,nuk,1);                    }                }            }        }    int ans=0;    sumd[0]=t+1;    while(d[0]<=t)        ans+=sap(0,inf);    printf("%d\n",ans);}int main(){    read();    work();    return 0;}


原创粉丝点击