最近房地产商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;
}

相关文章:

  • 2022-01-01
  • 2021-08-29
  • 2021-07-04
  • 2021-05-28
  • 2021-07-03
  • 2022-12-23
  • 2022-12-23
  • 2021-06-11
猜你喜欢
  • 2022-12-23
  • 2021-10-31
  • 2021-11-25
  • 2021-07-14
  • 2021-08-25
  • 2021-08-11
  • 2022-01-29
相关资源
相似解决方案