[BZOJ2007][NOI2010]海拔

bzoj
luogu

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;
}
posted @ 2018-04-02 21:56  租酥雨  阅读(117)  评论(0编辑  收藏  举报