[BZOJ2007][NOI2010]海拔
sol
显然你只会给每个地点的海拔设成\(0\)或\(1\)吧。
而且\(0\)和\(1\)还一定会是一个联通块。
所以题目相当于是要求送左上点到右下点的最小割。
类似bzoj1001狼抓兔子,把平面图最小割转化成对偶图最短路。
其实这个东西很好理解。把平面图和对偶图画出来,每一条\(S\)到\(T\)的路径都对应着一个割。所以最短路即最小割。
\(Dijkstra\)跑得挺快的吧。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define pii pair<int,int>
#define mk make_pair
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 1005;
int n,id[N][N],S,T,tot,to[N*N],nxt[N*N],ww[N*N],head[N*N],cnt,dis[N*N],vis[N*N];
priority_queue<pii,vector<pii>,greater<pii> >Q;
void link(int u,int v,int w)
{
to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;
head[u]=cnt;
}
int Dijkstra()
{
memset(dis,63,sizeof(dis));
dis[S]=0;Q.push(mk(0,S));
while (!Q.empty())
{
int u=Q.top().second;Q.pop();
if (vis[u]) continue;vis[u]=1;
for (int e=head[u];e;e=nxt[e])
if (dis[to[e]]>dis[u]+ww[e])
dis[to[e]]=dis[u]+ww[e],Q.push(mk(dis[to[e]],to[e]));
}
return dis[T];
}
int main()
{
n=gi();
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
id[i][j]=++tot;
S=++tot;T=++tot;
for (int i=1;i<=n;++i) id[i][0]=id[n+1][i]=S,id[0][i]=id[i][n+1]=T;
for (int i=1;i<=n+1;++i)
for (int j=1;j<=n;++j)
link(id[i][j],id[i-1][j],gi());
for (int i=1;i<=n;++i)
for (int j=1;j<=n+1;++j)
link(id[i][j-1],id[i][j],gi());
for (int i=1;i<=n+1;++i)
for (int j=1;j<=n;++j)
link(id[i-1][j],id[i][j],gi());
for (int i=1;i<=n;++i)
for (int j=1;j<=n+1;++j)
link(id[i][j],id[i][j-1],gi());
printf("%d\n",Dijkstra());
return 0;
}