传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2132
Description
最近房地产商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求出一个收益最大的方案么?
Input
输入第一行为两个整数,分别为正整数N和M,分别表示区域的行数和列数;第2到N+1列,每行M个整数,表示商业区收益矩阵A;第N+2到2N+1列,每行M个整数,表示工业区收益矩阵B;第2N+2到3N+1行,每行M个整数,表示相邻额外收益矩阵C。第一行,两个整数,分别是n和m(1≤n,m≤100);
任何数字不超过1000”的限制
Output
输出只有一行,包含一个整数,为最大收益值。
Sample Input
3 3
1 2 3
4 5 6
7 8 9
9 8 7
6 5 4
3 2 1
1 1 1
1 3 1
1 1 1
Sample Output
81
【数据规模】
对于100%的数据有N,M≤100
这道题乍一眼看可以用最小割的基本模型做,但因为有一个combo的问题(也就是内个k*Cij啦)所以尽量考虑相邻的不一样,那么就需要黑白染色啦(也就是相邻的性质不一样)对于黑点建正图(st->i权值为Ai,i->ed权值为Bi)[这里i不是坐标,是点的编号],白点建反图(st->i权值为Bi,i->ed权值为Ai),对于正反图的定义也可以倒过来的,在相邻的点之间建边权值为Ci+Cj,如果割两点之间连边,那就相当于放弃了combo,选择了相邻块同色。
做完我整个人也最小割了…..
code:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int dx[]={0,0,1,-1};
const int dy[]={-1,1,0,0};
const int M=1e9;
struct node
{
int x,y,next,c,other;
}a[2100000]; int len,last[2100000];
int st,ed;
inline void ins(int x,int y,int c)
{
int k1,k2;
len++; k1=len;
a[len].x=x;a[len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
len++; k2=len;
a[len].x=y;a[len].y=x;a[len].c=0;
a[len].next=last[y];last[y]=len;
a[k1].other=k2;
a[k2].other=k1;
}
int list[2100000],head,tail,h[11000];
inline bool bfs()
{
memset(h,0,sizeof(h)); h[st]=1;
list[1]=st,head=1,tail=2;
while(head!=tail)
{
int x=list[head];
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(a[k].c>0 && h[y]==0)
{
h[y]=h[x]+1;
list[tail++]=y;
}
}
head++;
}
if(h[ed]>0) return true;
else return false;
}
inline int findflow(int x,int f)
{
if(x==ed) return f;
int s=0,t;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(a[k].c>0 && h[y]==h[x]+1 && s<f)
{
t=findflow(y,min(f-s,a[k].c));
s+=t; a[k].c-=t; a[a[k].other].c+=t;
}
}
if(s==0) h[x]=0;
return s;
}
int dinic()
{
int s=0;
while(bfs())
{
s+=findflow(st,M);
}
return s;
}
int n,m;
inline int get(int x,int y){return (x-1)*m+y;}
int A[1100][1100],b[1100][1100],c[1100][1100];
int main()
{
scanf("%d%d",&n,&m);
st=n*m+1,ed=st+1;
int sum=0;
len=0;memset(last,0,sizeof(last));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&A[i][j]);sum+=A[i][j];
if((i+j)&1) ins(st,get(i,j),A[i][j]);
else ins(get(i,j),ed,A[i][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&b[i][j]);sum+=b[i][j];
if((i+j)&1) ins(get(i,j),ed,b[i][j]);
else ins(st,get(i,j),b[i][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int x;scanf("%d",&c[i][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
for(int t=0;t<4;t++)
{
int tx=i+dx[t],ty=j+dy[t];
if(tx>=1 && tx<=n && ty>=1 && ty<=m)
{
int t1=get(i,j),t2=get(tx,ty);
ins(t1,t2,c[i][j]+c[tx][ty]);
sum+=c[i][j];
}
}
}
printf("%d\n",sum-dinic());
return 0;
}