歌名 - 歌手
0:00

    【2011集训队出题】圈地计划

    题目

      最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地。据了解,这块土地是一块矩形的区域,可以纵横划分为N×M块小区域。GDOI要求将这些区域分为商业区和工业区来开发。根据不同的地形环境,每块小区域建造商业区和工业区能取得不同的经济价值。更具体点,对于第i行第j列的区域,建造商业区将得到Aij收益,建造工业区将得到Bij收益。另外不同的区域连在一起可以得到额外的收益,即如果区域(I,j)相邻(相邻是指两个格子有公共边)有K块(显然K不超过4)类型不同于(I,j)的区域,则这块区域能增加k×Cij收益。经过Tiger.S教授的勘察,收益矩阵A,B,C都已经知道了。你能帮GDOI求出一个收益最大的方案么?

    分析

    二元关系,最小割。
    先把总收益求出来,在减去最小割。
    连边,对于两个相邻的点x,y。
    源点点S向x连a[x]的边,向y连b[y]的边。
    x向汇点T连b[x]的边,y向汇点T连a[y]的边。
    x、y之间连c[x]+c[y]的双向边。

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