平面图
若对于一个在平面上的图 \(G\) ,有 \(\forall u,v\in G\),其交点为 \(G\) 顶点,则称这个图为平面图。
对偶图
在原图的边隔开的每个面上选一个点,若两个点相连穿过且仅穿过一条边就将它俩连起来,这条边的边权即为原图被穿过的边的边权
\(↑\)懒得画图也不太会用人类语言描述,感性理解(
因为可以将对偶图的边权看作删除原图的边的代价,所以对偶图上的最短路就是原图最小割
对偶图建图是怎么回事呢?对偶图相信大家都很熟悉,但是对偶图建图是怎么回事呢,下面就让我们一起了解吧。
对偶图建图,其实就是将平面图转换为对偶图,大家可能会很惊讶对偶图怎么会建图呢?但事实就是这样,我也感到非常惊讶。
这就是关于对偶图建图的事情了,大家有什么想法呢。
//4001
#include <bits/stdc++.h>
using namespace std;
long long read()
{
long long res=0,p=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')p=-1; ch=getchar();}
while(isdigit(ch)) res=res*10+ch-'0',ch=getchar();
return res*p;
}
const int maxn=2010,inf=0x3f3f3f3f;
int n,m,sumn;
long long ans;
int line[maxn][maxn],cur[maxn][maxn],row[maxn][maxn];
long long dis[maxn*maxn*2];
bool vis[maxn*maxn*2];
int s,t;
int head[maxn*maxn*2],cnt;
struct note
{
int nxt,to,val;
}ed[maxn*maxn*4];
void add(int u,int v,int w)
{
ed[++cnt].nxt=head[u],ed[cnt].to=v,ed[cnt].val=w,head[u]=cnt;
}
int id(int x,int y,int flag)
{
if(((x-1)*m+y)*2+flag==t) cout<<x<<" "<<y<<endl;
return ((x-1)*m+y)*2+flag;
}
struct node
{
int pos,dis;
bool operator < (const node &x) const
{
return x.dis<dis;
}
};
priority_queue<node> q;
void dij()
{
q.push((node){s,0}),memset(dis,0x3f,sizeof(dis)),dis[s]=0;
while(!q.empty())
{
node now=q.top();q.pop();
int u=now.pos;
if(vis[u]) continue ;
vis[u]=1;
for(int i=head[u];i;i=ed[i].nxt)
{
int v=ed[i].to,w=ed[i].val;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
if(!vis[v]) q.push((node){v,dis[v]});
}
}
}
}
int main()
{
n=read(),m=read(),sumn=(n-1)*(m-1)*2,s=0,t=n*m*2+1;
if(n==1||m==1)
{
n=max(n,m),ans=inf;
for(int i=1;i<=n;++i) ans=min(ans,read());
cout<<ans;
return 0;
}
for(int i=1;i<=n;++i) for(int j=1;j<m;++j) line[i][j]=read();
for(int i=1;i<n;++i) for(int j=1;j<=m;++j) row[i][j]=read();
for(int i=1;i<n;++i) for(int j=1;j<m;++j) cur[i][j]=read();
for(int i=1;i<m;++i) add(id(1,i,0),t,line[1][i]),add(s,id(n-1,i,1),line[n][i]),add(id(n-1,i,1),s,line[n][i]),add(t,id(1,i,0),line[1][i]);
for(int i=1;i<n;++i) add(s,id(i,1,1),row[i][1]),add(id(i,m-1,0),t,row[i][m]),add(id(i,1,1),s,row[i][1]),add(t,id(i,m-1,0),row[i][m]);
for(int i=1;i<n;++i)
{
for(int j=1;j<m;++j)
{
if(i>1) add(id(i,j,0),id(i-1,j,1),line[i][j]);
if(j<m-1) add(id(i,j,0),id(i,j+1,1),row[i][j+1]);
if(j>1) add(id(i,j,1),id(i,j-1,0),row[i][j]);
if(i<n-1) add(id(i,j,1),id(i+1,j,0),line[i+1][j]);
add(id(i,j,1),id(i,j,0),cur[i][j]),add(id(i,j,0),id(i,j,1),cur[i][j]);
}
}
dij();
cout<<dis[t];
return 0;
}