题解 P1935 【[国家集训队]圈地计划】

· · 题解

唔姆

正如各位大佬所说,这题和P1646很像,但我觉得真正想通了,这题比P1646容易鸭 (我甚至有了抄我以前写的P1646题解的想法了

一点都没P1646愉♂悦

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define MAXN 100050
#define MAXM 150005
using namespace std;
int head[MAXN],next[MAXM*2],to[MAXM*2],w[MAXM*2];
int n,m,S,T;
int cnt=-1;
int deep[MAXN];
void link(int a,int b,int c){
     cnt++;
     w[cnt]=c;
     next[cnt]=head[a];
     to[cnt]=b;
     head[a]=cnt;
     cnt++;
     w[cnt]=0;
     next[cnt]=head[b];
     to[cnt]=a;
     head[b]=cnt;
}
bool bfs(){
     memset(deep,0,sizeof(deep));
     queue<int> q;
     while(!q.empty())q.pop();
     q.push(S);
     deep[S]=1;
     while(!q.empty()){
                       int now=q.front();
                       q.pop();
                       for(int i=head[now];i!=-1;i=next[i]){
                               if (w[i]&&!deep[to[i]]){
                                                       deep[to[i]]=deep[now]+1;
                                                       q.push(to[i]);
                               }
                       }
     }
     if (deep[T])return 1;else return 0;
}
int dinic(int now,int last){
    if (now==T||!last)return last;
    int ret=0;
    for(int i=head[now];i!=-1;i=next[i]){
            if(deep[to[i]]-1==deep[now]&&w[i]){
                                               int zgl=dinic(to[i],min(w[i],last-ret));
                                               if (zgl){
                                                        w[i]-=zgl;
                                                        w[i^1]+=zgl;     
                                                        ret+=zgl;
                                               }
            }
    }
    if (!ret)deep[now]=-1;
    return ret;
}
int num(int a,int b){
    return m*(a-1)+b;
}
int c[200][200];
int main(){
    cin>>n>>m;
    S=0;T=MAXN-1;
    int a;
    memset(head,-1,sizeof(head));
    long long sum=0;
    for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                    scanf("%d",&a);
                    if ((i+j)&1)link(S,num(i,j),a);
                    else link(num(i,j),T,a);
                    sum+=a;
            }
    }
    for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                    scanf("%d",&a);
                    if ((i+j)&1)link(num(i,j),T,a);
                    else link(S,num(i,j),a);
                    sum+=a;
            }
    }
    for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                    scanf("%d",&c[i][j]);
    int tx[]={0,-1,0,1},ty[]={1,0,-1,0};
    for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                    for(int k=0;k<4;k++){
                            int xx=i+tx[k],yy=j+ty[k];
                            if (xx<=0||xx>n)continue;
                            if (yy<=0||yy>m)continue;
                            link(num(i,j),num(xx,yy),c[i][j]+c[xx][yy]);
                            sum+=c[i][j];
                    }
            }
    }
    long long ans=0;
    while(bfs())
                 ans+=dinic(S,9999999);
    cout<<sum-ans;
    return 0;
}