最小割板子,注意的是边要开点的6倍,因为一个点三条路再乘2就是6.
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cctype>
#define inf 0x3f3f3f3f
#define ll long long
#define N 1010000
using namespace std;
queue<int> q;
int head[N*6],nxt[N*6],to[N*6],c[N*6],cur[N],depth[N],n,m,ans,ToT=1;
int read() {
int ret=0;char ch=getchar();
for (;!isdigit(ch);ch=getchar());
for (;isdigit(ch);ch=getchar()) ret=ret*10+ch-'0';
return ret;
}
void add_edge(int x,int y,int z) {to[++ToT]=y;c[ToT]=z;nxt[ToT]=head[x];head[x]=ToT;}
void insert(int x,int y,int z){add_edge(x,y,z);add_edge(y,x,z);}
bool bfs() {
memset(depth,0,sizeof(depth));
depth[1]=1;q.push(1);
for (;q.size();) {
int x=q.front();q.pop();
for (int i=head[x];i;i=nxt[i])
if (depth[to[i]]==0&&c[i])
depth[to[i]]=depth[x]+1,q.push(to[i]);
}
return depth[n*m];
}
int dfs(int x,int f) {
if (x==n*m) return f;
int w=0,used=0;
for (int& i=cur[x];i;i=nxt[i]) {
if (depth[to[i]]==depth[x]+1) {
w=f-used;w=dfs(to[i],min(c[i],w));
used+=w;c[i]-=w;c[i^1]+=w;
if (used==f) return f;
}
}
if (used==0) depth[x]=-1;
return used;
}
int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<m;j++) {
int x=read();
insert((i-1)*m+j,(i-1)*m+j+1,x);
}
for (int i=1;i<n;i++)
for (int j=1;j<=m;j++) {
int x=read();
insert((i-1)*m+j,i*m+j,x);
}
for (int i=1;i<n;i++)
for (int j=1;j<m;j++) {
int x=read();
insert((i-1)*m+j,i*m+j+1,x);
}
for (;bfs();) {
for (int i=1;i<=n*m;i++) cur[i]=head[i];
ans+=dfs(1,inf);
}
printf("%d\n",ans);
return 0;
}