容易发现答案就是最小割
由最小割最大流定理知答案就是原图的最大流
直接上就行了
建图时要注意边是无向的,反向边流量不为
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+5,maxe=6e6+5;
int n,m,s,t,ans,tot=1,idx[1005][1005],son[maxe],cur[maxn],w[maxe],nxt[maxe],lnk[maxn],d[maxn],que[maxn];
inline int read(){
int ret=0,fh=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')fh=-fh;ch=getchar();}
while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*fh;
}
bool BFS(){
memset(d,-1,sizeof(d));
d[s]=1,que[1]=s;
int hd=0,tl=1;
while(hd<tl){
int x=que[++hd];
for(int j=lnk[x];j;j=nxt[j]){
int v=son[j];
if(w[j]&&d[v]==-1){
d[v]=d[x]+1;
que[++tl]=v;
}
}
}
return d[t]!=-1;
}
int DFS(int x,int f){
if(x==t) return f;
int f0=0;
for(int&j=cur[x];j;j=nxt[j]){
int v=son[j];
if(w[j]&&d[v]==d[x]+1){
int k=DFS(v,min(f,w[j]));
if(k>0){
w[j]-=k,w[j^1]+=k;
f-=k,f0+=k;
if(!f) break;
}
}
}
return f0;
}
void add_e(int x,int y,int z){son[++tot]=y,w[tot]=z,nxt[tot]=lnk[x],lnk[x]=tot;}
int main(){
freopen("P1001.in","r",stdin);
freopen("P1001.out","w",stdout);
n=read(),m=read();
int cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
idx[i][j]=++cnt;
}
s=idx[1][1],t=idx[n][m];
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++){
int x=read();
add_e(idx[i][j],idx[i][j+1],x);
add_e(idx[i][j+1],idx[i][j],x);
}
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++){
int x=read();
add_e(idx[i][j],idx[i+1][j],x);
add_e(idx[i+1][j],idx[i][j],x);
}
for(int i=1;i<n;i++)
for(int j=1;j<m;j++){
int x=read();
add_e(idx[i][j],idx[i+1][j+1],x);
add_e(idx[i+1][j+1],idx[i][j],x);
}
while(BFS()){
memcpy(cur,lnk,sizeof(cur));
ans+=DFS(s,2e9);
}
printf("%d\n",ans);
return 0;
}