传送门:

BZOJ

洛谷


Description

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


Input

输入第一行为两个整数,分别为正整数NM,分别表示区域的行数和列数;

2N+1列,每行M个整数,表示商业区收益矩阵A

N+22N+1列,每行M个整数,表示工业区收益矩阵B

2N+23N+1行,每行M个整数,表示相邻额外收益矩阵C

任何数字不超过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 \le 100


解题思路:

我们可以将题意转化一下,变成如果相同的话可以有额外奖励,我们只需要将原问题的不同转化为相同就好了。

那么我们黑白染色,将黑白中的一种点的A值和B值交换一下就将不同转化为相同了。

Code:

/*Program from Luvwgyx*/
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=1e9;
const int maxn=1e2+10;
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
struct node{int to,nxt,w;}e[(int)1e5];
int S,T,tot=1,maxflow,head[maxn*maxn],d[maxn*maxn];queue<int >q;
int n,m,sum,a[maxn][maxn],b[maxn][maxn],c[maxn][maxn],f[maxn][maxn];
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void print(int x){
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar(x%10+'0');
}
void write(int x){print(x);puts("");}
int get(int x,int y){return m*(x-1)+y;}
void add(int u,int v,int w){e[++tot].to=v;e[tot].w=w;e[tot].nxt=head[u];head[u]=tot;}
bool bfs(){
    memset(d,0,sizeof(d));
    while(!q.empty())q.pop();
    q.push(S);d[S]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head[x],v=e[i].to;i;i=e[i].nxt,v=e[i].to)
            if(e[i].w&&!d[v]){
                q.push(v);d[v]=d[x]+1;
                if(v==T)return 1;
            }
    }return 0;
}
int dinic(int x,int flow){
    if(x==T)return flow;
    int rest=flow,w;
    for(int i=head[x],v=e[i].to;i&&rest;i=e[i].nxt,v=e[i].to)
        if(e[i].w&&d[v]==d[x]+1){
            w=dinic(v,min(rest,e[i].w));
            if(!w)d[v]=0;
            e[i].w-=w;e[i^1].w+=w;rest-=w;
        }
    return flow-rest;
}
int main(){
    n=read();m=read();S=0;T=10001;
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=read();
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)b[i][j]=read();
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)c[i][j]=read();
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if((i+j)&1)f[i][j]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(f[i][j])swap(a[i][j],b[i][j]);
            add(S,get(i,j),a[i][j]);add(get(i,j),S,0);sum+=a[i][j];
            add(get(i,j),T,b[i][j]);add(T,get(i,j),0);sum+=b[i][j];
            if(f[i][j]){
                for(int k=0;k<4;k++){
                    int xx=i+dx[k],yy=j+dy[k];
                    if(xx<1||xx>n||yy<1||yy>m)continue;
                    add(get(i,j),get(xx,yy),c[i][j]+c[xx][yy]);
                    add(get(xx,yy),get(i,j),c[i][j]+c[xx][yy]);
                    sum+=c[i][j]+c[xx][yy];
                }
            }
        }
    while(bfs())maxflow+=dinic(S,inf);
    write(sum-maxflow);
    return 0;
}