Description
“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n∗m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。
Input
文件的第一行包含两个整数n和
文件中仅包含一个整数ans,代表篱笆的最短长度。
SampleInput
2
2
1
SampleOutput
2
数据范围
30%的数据 n,m≤20
100%的数据 n,m≤100
Solution
看到题目要求把图中具有两种属性的点完全分开(即羊和狼),就会想到图的割……
割边集一边没有狼,一边没有羊。
这个问题就变成了图的最小割,建图的方法就是原图相邻的方块连边,然后羊和狼分别连源或汇。
在所有的狼或羊都连了源或汇时,狼与狼或羊与羊之间的连边是一定不会成为割边的(简单想想就知道了)
所以这样跑出来的最小割就是我们的答案
#include<stdio.h>
#define min(a,b) (a<b?a:b)
#define lim 100000000
#define N 10005
#define M 150000
struct edge{int v,n,c;}e[M];
int tot=1,E,S,n,m,ans,s[N],time[N],times,p[N],d[N];
inline void addedge(const int &u,const int &v,const int &c)
{
e[++tot].v=v;
e[tot].n=s[u];
e[tot].c=c;
s[u]=tot;
e[++tot].v=u;
e[tot].n=s[v];
s[v]=tot;
}
inline bool bfs()
{
time[S]=++times;
p[S]=1;
d[0]=S;
for (int h=0,t=0;h<=t;h++) for (int i=s[d[h]];i;i=e[i].n) if (time[e[i].v]!=times && 0<e[i].c)
{
time[e[i].v]=times;
p[e[i].v]=p[d[h]]+1;
d[++t]=e[i].v;
}
return time[E]==times;
}
int dfs(const int &u,int flow)
{
if (u==E) return flow;
int f=flow,g=0;
for (int i=s[u];i;i=e[i].n)
{
int tmp=0;
if (p[e[i].v]==p[u]+1 && 0<e[i].c && (tmp=dfs(e[i].v,min(e[i].c,f))))
{
f-=tmp;
g+=tmp;
e[i].c-=tmp;
e[i^1].c+=tmp;
}
}
return g;
}
int main()
{
scanf("%d%d",&n,&m);
E=(S=n*m+1)+1;
for (int i=1,c;i<=n;i++) for (int j=1;j<=m;j++)
{
scanf("%d",&c);
if (j<m) addedge(m*(i-1)+j,m*(i-1)+j+1,1),addedge(m*(i-1)+j+1,m*(i-1)+j,1);
if (i<n) addedge(m*(i-1)+j,m*i+j,1),addedge(m*i+j,m*(i-1)+j,1);
if (c==1) addedge(S,m*(i-1)+j,lim);
if (c==2) addedge(m*(i-1)+j,E,lim);
}
while (bfs()) ans+=dfs(S,lim);
printf("%d",ans);
}