[ZJOI2009]狼和羊的故事——最大流

题目描述

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

猜你喜欢

转载自www.cnblogs.com/Khada-Jhin/p/9115045.html