【bzoj2007】 Noi2010—海拔

http://www.lydsy.com/JudgeOnline/problem.php?id=2007 (题目链接)

题意

  $(n+1)*(n+1)$的网格图上,相邻两点间有一些人流。左上角点的海拔$0$,右下角海拔$1$,没单位人流从海拔低的地方走到海拔高的地方会消耗对应的体力。问最少消耗多少体力。

Solution

  最小割很显然,转为对偶图跑Dijkstra就好了。

  用pair写个堆各种奇怪的错误是smg,建图还建错了,今天晚上不适合写题= =

细节

  priority_queue默认大根堆= =。

代码

// bzoj2007
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf (1ll<<30)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;

const int maxn=1000010;
int head[maxn],dis[maxn],vis[maxn],n,S,T,cnt;
struct edge {int to,next,w;}e[maxn<<2];

void link(int u,int v,int w) {
	e[++cnt]=(edge){v,head[u],w};head[u]=cnt;
}
int Dijkstra() {
	for (int i=S;i<=T;i++) dis[i]=inf;dis[S]=0;
	priority_queue<pair<int,int> >q;q.push(pair<int,int>(0,S));
	while (!vis[T]) {
		pair<int,int> x=q.top();q.pop();
		if (vis[x.second]) continue;
		vis[x.second]=1;
		for (int i=head[x.second];i;i=e[i].next)
			if (!vis[e[i].to] && dis[e[i].to]>e[i].w-x.first) {
				dis[e[i].to]=e[i].w-x.first;
				q.push(pair<int,int>(-dis[e[i].to],e[i].to));
			}
	}
	return dis[T];
}
int main() {
	scanf("%d",&n);
	S=0,T=n*n+1;
	for (int i=0;i<=n;i++)
		for (int x,j=1;j<=n;j++)
			scanf("%d",&x),link(max(S,(i-1)*n+j),min(T,i*n+j),x);
	for (int i=0;i<n;i++)
		for (int x,j=1;j<=n+1;j++)
			scanf("%d",&x),link(j==n+1 ? S : i*n+j,j==1 ? T : i*n+j-1,x);
	for (int i=0;i<=n;i++)
		for (int x,j=1;j<=n;j++)
			scanf("%d",&x),link(min(T,i*n+j),max(S,(i-1)*n+j),x);
	for (int i=0;i<n;i++)
		for (int x,j=1;j<=n+1;j++)
			scanf("%d",&x),link(j==1 ? T : i*n+j-1,j==n+1 ? S :i*n+j,x);
	printf("%d",Dijkstra());
	return 0;
}

 

posted @ 2017-03-26 22:56  MashiroSky  阅读(284)  评论(0编辑  收藏  举报