qwq感觉是平面图最小割转对偶图的板子题。
这里主要说一下关于转对偶图的时候,单向边和双向边的问题。
首先原图中的每一条边,都应该对应的是对偶图中的一个单向边
我们来对比 N O I 2010 海 拔 和 B J O I 2006 狼 抓 兔 子 NOI2010海拔和BJOI2006狼抓兔子 NOI2010海拔和BJOI2006狼抓兔子。
海拔这个题,对于
(
u
,
v
)
(u,v)
(u,v)之间的边,两条边的边权是不同的。所以我们要对于原图中每一条边建一条对偶图,至于方向,我大概只会感性理解
大概就是 你考虑如果对偶图中的S在左下角,那么原图中从左到右的边就应该转化成从下到上,以此类推
QWQ
而狼抓兔子这个题,之所以要建双向边,是因为其实本质上还是两个单向边分别建了两条对偶图中的单向边,但是因为这个题中,原图的边就是无向(或者说两个方向是完全一致的),所以应该直接建双向边。
总之就感觉这种东西很神奇,转对偶图之前一定要想好方向再建
(还要注意点的编号)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
#define pa pair<int,int>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 2e6+1e2;
const int maxm = 1e7+1e2;
int point[maxn],nxt[maxm],to[maxm];
int val[maxm],cnt,n,m;
int dis[maxn],vis[maxn];
int s,t;
priority_queue<pa,vector<pa>,greater<pa> > q;
int num;
void addedge(int x,int y,int w)
{
// cout<<"edge:"<<cnt+1<<" "<<x<<" "<<y<<endl;
nxt[++cnt]=point[x];
to[cnt]=y;
val[cnt]=w;
point[x]=cnt;
}
void dijkstra(int s)
{
memset(dis,127/3,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push(mk(0,s));
while (!q.empty())
{
int x = q.top().second;
q.pop();
if (vis[x]) continue;
vis[x]=1;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (dis[p]>dis[x]+val[i])
{
dis[p]=dis[x]+val[i];
q.push(mk(dis[p],p));
}
}
}
}
int getnum(int x,int y,int opt)
{
if (x==0) return t;
if (x==n) return s;
if (y==0) return s;
if (y==m) return t;
return (x-1)*(m-1)+y+opt*num;
}
int main()
{
n=read(),m=read();
s=maxn-10;
t=s+1;
num = (n-1)*(m-1);
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m-1;j++)
{
int x=read();
addedge(getnum(i,j,0),getnum(i-1,j,1),x);
addedge(getnum(i-1,j,1),getnum(i,j,0),x);
}
}
for (int i=1;i<=n-1;i++)
{
for (int j=1;j<=m;j++)
{
int x=read();
addedge(getnum(i,j-1,0),getnum(i,j,1),x);
addedge(getnum(i,j,1),getnum(i,j-1,0),x);
}
}
for (int i=1;i<=n-1;i++)
for (int j=1;j<=m-1;j++)
{
int x=read();
addedge(getnum(i,j,1),getnum(i,j,0),x);
addedge(getnum(i,j,0),getnum(i,j,1),x);
}
dijkstra(s);
cout<<dis[t]<<endl;
return 0;
}