歌名 - 歌手
0:00

    【ZJOI2009】狼和羊的故事

    题目

      “狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......”
      Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干!
      Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。
      通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。
      Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。

    分析

    因为用篱笆将狼和羊分开,也就是将狼和羊割成两块,那么考虑做最小割。
    连边:源点s向每只狼连一条无穷大的边,然后每只羊向汇点t连一条无穷大的边,接着每只狼和每块空地向相邻的每块空地和每只羊连一条1的边。

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    const int maxlongint=2147483647;
    const int mo=1000000007;
    const int N=11105;
    using namespace std;
    int next[N*5],last[N],f[N*5],to[N*5],up[N*5],tot,n,m,a[111][111],d[N*10],dis[N];
    int zz[4][2]=
    {
     {0,1},
     {1,0},
     {0,-1},
     {-1,0}
    };
    int bj(int x,int y,int z)
    {
    	next[++tot]=last[x];
    	last[x]=tot;
    	to[tot]=y;
    	f[tot]=z;
    	
    	up[tot]=++tot;
    	up[tot]=tot-1;
    	
    	next[tot]=last[y];
    	last[y]=tot;
    	to[tot]=x;
    	f[tot]=0;
    	
    }
    int bfs()
    {
    	memset(dis,0,sizeof(dis));
    	d[1]=0;
    	dis[0]=1;
    	int head=0,tail=1,k;
    	while(head<tail)
    	{
    		k=d[++head];
    		for(int i=last[k];i;i=next[i])
    		{
    			int j=to[i];
    			if(f[i]>0 && !dis[j])
    			{
    				dis[j]=dis[k]+1;
    				d[++tail]=j;
    			}
    		}
    	}
    	if(!dis[n*m+n]) return false;
    		else return true;
    }
    int aug(int x,int y)
    {
    	if(x==n*m+n) return y;
    	for(int i=last[x];i;i=next[i])
    	{
    		int j=to[i];
    		if(dis[x]+1==dis[j] && f[i]>0)
    		{
    			int o=aug(j,min(y,f[i]));
    			if(o>0)
    			{
    				f[i]-=o;
    				f[up[i]]+=o;
    				return o;
    			}
    		}
    	}
    	return 0;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    		{
    			int pos=(i-1)*m+j;
    			scanf("%d",&a[i][j]);
    			if(a[i][j]==1)
    				bj(0,pos,maxlongint);
    			if(a[i][j]==2)
    				bj(pos,n*m+n,maxlongint);
    		}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			for(int k=0;k<=3;k++)
    			{
    				int xx=i+zz[k][0],yy=j+zz[k][1];
    				if(xx<1 || yy<1 || xx>n || yy>m) continue;
    				int pos=(i-1)*m+j,pos1=(xx-1)*m+yy;
    				if(a[i][j]!=2)
    					if(a[xx][yy]!=1) bj(pos,pos1,1);
    			}
    	int ans=0;
    	while(bfs()) 
    		ans+=aug(0,maxlongint);
    	cout<<ans<<endl;
    }
    
    posted @ 2018-05-21 12:13  无尽的蓝黄  阅读(229)  评论(0编辑  收藏  举报