參考 https://blog.csdn.net/MaxMercer/article/details/77976666
平面圖纔有對偶圖。
平面圖是能展開成一張 -> 各邊只在頂點處相交的圖 <-的圖。
平面圖的對偶圖是將這個圖G的每一個面做新圖G‘的點,在 每一條邊兩邊的面之間連邊的圖。
隨便找個圖連一下會發現,對偶圖中的每一個環對應原圖中的一個割。
盜了一張論文ppt裏的圖。原圖爲藍色,對偶圖爲粉色。
現在我想求原圖S,T之間的最小割。假設原圖S,T之間有一條邊,對偶圖的S'和T’之間就會有一條切開這條邊的邊。只要我補上一條S'到T'之間的路徑,就形成了一個能把原圖S,T切開的環。由於要求最小割,那條假設的路徑權值可以不管,所以問題就轉化成了求對偶圖S'到T'的最短路徑問題。
我習慣spfa就寫了spfa。
/**************************************************************
Problem: 1001
User: adelais
Language: C++
Result: Accepted
Time:2980 ms
Memory:96996 kb
****************************************************************/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2000005;
const ll INF=1e18;
int n,m,cnt;
struct node{
int to,ne,w;
}e[maxn*3];
int head[maxn];
ll dis[maxn];
bool fl[maxn];
queue<int>q;
void add(int u,int v,int w){
e[cnt].to=v;e[cnt].w=w;
e[cnt].ne=head[u];head[u]=cnt++;
e[cnt].to=u;e[cnt].w=w;
e[cnt].ne=head[v];head[v]=cnt++;
}
ll spfa(int s,int t){
while(!q.empty()) q.pop();
q.push(s);
dis[s]=0;
fl[s]=1;
while(!q.empty()){
int now=q.front();q.pop();
fl[now]=0;
for(int i=head[now];~i;i=e[i].ne){
int v=e[i].to;
if(dis[v]>dis[now]+e[i].w){
dis[v]=dis[now]+e[i].w;
if(!fl[v]){
fl[v]=1;q.push(v);
}
}
}
}
return dis[t];
}
int main(){
scanf("%d%d",&n,&m);
int s=(n-1)*(m-1)*2+1,t=s+1;
for(int i=0;i<=t;i++) head[i]=-1,dis[i]=INF;
int x;
for(int i=0;i<n;i++){
for(int j=1;j<=m-1;j++){
scanf("%d",&x);
if(i==0) add(s,i*(m-1)*2+j*2,x);
else if(i==n-1) add((i-1)*(m-1)*2+j*2-1,t,x);
else add((i-1)*(m-1)*2+j*2-1,i*(m-1)*2+j*2,x);
}
}
for(int i=0;i<n-1;i++){
for(int j=1;j<=m;j++){
scanf("%d",&x);
if(j==1) add(t,i*(m-1)*2+j*2-1,x);
else if(j==m) add(i*(m-1)*2+j*2-2,s,x);
else add(i*(m-1)*2+j*2-2,i*(m-1)*2+j*2-1,x);
}
}
for(int i=0;i<n-1;i++){
for(int j=1;j<=m-1;j++){
scanf("%d",&x);
add(i*(m-1)*2+j*2-1,i*(m-1)*2+j*2,x);
}
}
ll ans=spfa(s,t);
printf("%lld\n",ans);
return 0;
}