挺有意思的结论,对偶图中的一个环对应原图中一种割,把边流量转为距离跑最短路就是最小割了
//#include<bits/stdc++.h>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<iostream>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
using namespace std;
const double pi=acos(-1.0);
#define ll long long
#define pb push_back
#define sqr(a) ((a)*(a))
#define dis(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y))
const double eps=1e-10;
const int maxn=2e6+56;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int n,m;
int from,to;
struct EDGE{int v,w;};
vector<EDGE>G[maxn];
void addedge(int u,int v,int w){
G[u].pb((EDGE){v,w});
G[v].pb((EDGE){u,w});
}
struct NODE{
int v,d;
friend bool operator<(NODE a,NODE b){return a.d>b.d;}
};
int d[maxn],vis[maxn];
void dij(int from,int to){
for(int i=0;i<maxn;i++)d[i]=inf;
d[from]=0;
priority_queue<NODE>Q;
NODE now=(NODE){from,0};
Q.push(now);
while(!Q.empty()){
NODE now=Q.top();Q.pop();
int u=now.v;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<G[u].size();i++){
if(d[G[u][i].v]>d[u]+G[u][i].w){
d[G[u][i].v]=d[u]+G[u][i].w;
NODE nxt=(NODE){G[u][i].v,d[G[u][i].v]};
Q.push(nxt);
}
}
}
printf("%d\n",d[to]);
}
int main(){
while(~scanf("%d%d",&n,&m)){
from=0;to=2*(n-1)*(m-1)+1;
int x,y,cost;
for(int i=1;i<=n;i++){
for(int j=1;j<m;j++){
scanf("%d",&cost);
x=i==1?from:(2*(i-1)-1)*(m-1)+j;
y=i==n?to:(2*(i-1))*(m-1)+j;
addedge(x,y,cost);
}
}
for(int i=1;i<n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&cost);
x=j==1?to:(2*(i-1))*(m-1)+j-1;
y=j==m?from:(2*(i-1))*(m-1)+j-1+m;
addedge(x,y,cost);
}
}
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
scanf("%d",&cost);
x=(2*(i-1))*(m-1)+j;
y=(2*(i-1)+1)*(m-1)+j;
addedge(x,y,cost);
}
}
dij(from,to);
}
}