【bzoj2007】 Noi2010—海拔

时间:2021-03-27 07:00:49

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;
}