[国家集训队]圈地计划
题目描述
最近房地产商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求出一个收益最大的方案么?
输入格式
输入第一行为两个整数,分别为正整数N和M,分别表示区域的行数和列数;
第2到N+1列,每行M个整数,表示商业区收益矩阵A;
第N+2到2N+1列,每行M个整数,表示工业区收益矩阵B;
第2N+2到3N+1行,每行M个整数,表示相邻额外收益矩阵C。
输出格式
输出只有一行,包含一个整数,为最大收益值。
输入输出样例
输入 #1复制
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
输出 #1复制
81
说明/提示
N, M ≤ 100; 0 ≤ Aij, Bij, Cij ≤ 1000
对于30%的数据有N, M ≤ 6
对于50%的数据有N, M ≤ 20
对于100%的数据有N, M ≤ 100
最小割求非黑即白问题。
考虑建图:这道题与其他很多题很相似,但是又有一些不同,其他题都是如果旁边的一样会增加某种值,但是这道题是不同的则会增加某种值。于是我们将横纵坐标之和为偶数的反着连边,那不就从不同,变成相同了吗?
然后对于相邻且不同的点,我们将这两个点之间连双向边,因为这样表示增加了某种值,为什么要连双向边呢?因为收益是双向的,但是我们要注意连边的时候,如果横纵坐标之和为奇数或者为偶数就跳过,因为会有重复的边。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N=4e4+10,M=2e5+10;
const int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int n,m,s,t,x,h[N],res,g[110][110];
int head[N],nex[M],to[M],w[M],tot=1;
inline void ade(int a,int b,int c){
to[++tot]=b; w[tot]=c; nex[tot]=head[a]; head[a]=tot;
}
inline void add(int a,int b,int c){
ade(a,b,c); ade(b,a,0);
}
inline int id(int x,int y){
return (x-1)*m+y;
}
inline int bfs(){
memset(h,0,sizeof h); queue<int> q; q.push(s); h[s]=1;
while(q.size()){
int u=q.front(); q.pop();
for(int i=head[u];i;i=nex[i]){
if(w[i]&&!h[to[i]]){
h[to[i]]=h[u]+1; q.push(to[i]);
}
}
}
return h[t];
}
int dfs(int x,int f){
if(x==t) return f;
int fl=0;
for(int i=head[x];i&&f;i=nex[i]){
if(w[i]&&h[to[i]]==h[x]+1){
int mi=dfs(to[i],min(f,w[i]));
w[i]-=mi; w[i^1]+=mi; fl+=mi; f-=mi;
}
}
if(!fl) h[x]=-1;
return fl;
}
inline int dinic(){
int res=0;
while(bfs()) res+=dfs(s,inf);
return res;
}
signed main(){
cin>>n>>m; t=n*m+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>x; res+=x;
if((i+j)&1) add(s,id(i,j),x);
else add(id(i,j),t,x);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>x; res+=x;
if((i+j)&1) add(id(i,j),t,x);
else add(s,id(i,j),x);
}
}
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>g[i][j];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if((i+j)&1) continue;
for(int k=0;k<4;k++){
int tx=i+dx[k]; int ty=j+dy[k];
if(tx<1||tx>n||ty<1||ty>m) continue;
res+=g[i][j]+g[tx][ty];
add(id(i,j),id(tx,ty),g[i][j]+g[tx][ty]);
add(id(tx,ty),id(i,j),g[i][j]+g[tx][ty]);
}
}
}
cout<<res-dinic()<<endl;
return 0;
}