题面
题意
给出一幅无向平面图,求s到t的最小割.
对偶图:将原图中的每一块区域当作一个点,原图上的每一条边转化为这条边两边区域之间的一条边,任何只在顶点处有交点的图(平面图)都有对偶图.
做法
这道题如果直接跑最大流,复杂度显然不对,但因为它存在对偶图,我们可以将题目转化为求左下角这块到右上角这块的最短路,对于样例可以这么建图
首先建对偶图
之后去掉原图就可以得到
可以发现从0点到13点((n-1)*(m-1) *2+1)的最短路恰好为最小割,这也是对偶图的一个性质,因此只要跑一边迪杰斯特拉即可.
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define C ch=getchar()
#define INF 0x3f3f3f3f
#define P pair<int,int>
#define mp make_pair<int,int>
#define fi first
#define se second
#define N 1000100
using namespace std;
int n,m,first[N<<1],bb,t,s,d[N<<1];
bool vis[N<<1];
char ch;
P tmp;
struct Bn
{
int to,next,quan;
} bn[N*6];
priority_queue<P,vector<P>,greater<P> >pq;
inline int read()
{
int res;
for(C;ch<'0';C);
for(res=ch-'0',C;ch>='0';res=res*10+ch-'0',C);
return res;
}
inline int ask(int u,int v,int w)
{
return (u-1)*(n-1)*2+(v-1)*2+w+1;
}
inline void add(int u,int v,int w)
{
bb++;
bn[bb].to=v;
bn[bb].next=first[u];
bn[bb].quan=w;
first[u]=bb;
}
inline void ad(int u,int v,int w)
{
add(u,v,w);
add(v,u,w);
}
int main()
{
memset(first,-1,sizeof(first));
int i,j,p,q;
m=read(),n=read();
t=(m-1)*(n-1)*2+1;
for(i=1; i<=m; i++)
{
for(j=1; j<n; j++)
{
p=read();
i==1?ad(ask(1,j,1),t,p):i==m?ad(ask(m-1,j,0),s,p):ad(ask(i-1,j,0),ask(i,j,1),p);
}
}
for(i=1; i<m; i++)
{
for(j=1; j<=n; j++)
{
p=read();
j==1?ad(s,ask(i,j,0),p):j==n?ad(ask(i,n-1,1),t,p):ad(ask(i,j-1,1),ask(i,j,0),p);
}
}
for(i=1; i<m; i++)
{
for(j=1; j<n; j++)
{
ad(ask(i,j,0),ask(i,j,1),read());
}
}
memset(d,0x3f,sizeof(d));
pq.push(mp(0,s));
d[s]=0;
for(; !pq.empty()&&!vis[t];)
{
tmp=pq.top();
pq.pop();
q=tmp.se;
if(vis[q]) continue;
vis[q]=1;
for(p=first[q]; p!=-1; p=bn[p].next)
{
if(d[bn[p].to]>d[q]+bn[p].quan)
{
d[bn[p].to]=d[q]+bn[p].quan;
pq.push(mp(d[bn[p].to],bn[p].to));
}
}
}
cout<<d[t];
}