【BZOJ 2132】 圈地计划

时间:2021-06-06 18:44:35

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
 
网络流的另一种建模姿势
二元组——>最小割
把图黑白染色,黑格工业连S,商业连T,白格反之。。。
黑白格相互之间连边,流量为c[x][y]+c[nx][ny]
 
 #include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
const int inf=,N=;
struct ee{int to,next,f;}e[N*N*N];
int head[N*N],q[N*N],dis[N*N],a[N][N],b[N][N],c[N][N],col[N][N];
int fx[]={,,,-},fy[]={,-,,};
int S,T=,n,m,cnt=,ans,w,mid,tot;
bool mark[N];
void ins(int u,int v,int w)
{cnt++;e[cnt].to=v;e[cnt].f=w;e[cnt].next=head[u];head[u]=cnt;}
void insert(int u,int v,int w)
{ins(u,v,w);ins(v,u,);} bool bfs(){
for (int i=;i<=T;i++) dis[i]=inf;
int h=,t=,now;
q[]=S;dis[S]=;
while(h!=t){
now=q[++h];
for (int i=head[now];i;i=e[i].next){
int v=e[i].to;
if (e[i].f&&dis[now]+<dis[v]){
dis[v]=dis[now]+;
if (v==T)return ;
q[++t]=v;
}
}
}
if (dis[T]==inf) return ; return ;
} int dinic(int now,int f){
if (now==T) return f;
int rest=f;
for (int i=head[now];i;i=e[i].next){
int v=e[i].to;
if (e[i].f&&dis[v]==dis[now]+&&rest){
int t=dinic(v,min(rest,e[i].f));
if (!t) dis[v]=;
e[i].f-=t;
e[i^].f+=t;
rest-=t;
}
}
return f-rest;
} void build(){
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if(col[i][j]) swap(a[i][j],b[i][j]);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
insert(S,(i-)*m+j,a[i][j]);
insert((i-)*m+j,T,b[i][j]);
ans+=a[i][j];ans+=b[i][j];
if(col[i][j])
for(int k=;k<;k++){
int nx=i+fx[k],ny=j+fy[k];
if(nx>n||nx<||ny>m||ny<) continue;
ins((nx-)*m+ny,(i-)*m+j,c[i][j]+c[nx][ny]);
ins((i-)*m+j,(nx-)*m+ny,c[i][j]+c[nx][ny]);
ans+=(c[i][j]+c[nx][ny]);
}
}
} int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) scanf("%d",&a[i][j]);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) scanf("%d",&b[i][j]);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) scanf("%d",&c[i][j]);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if ((i+j)&==) col[i][j]=;
build();
while(bfs()) tot+=dinic(S,inf);
printf("%d",ans-tot);
}