海拔(bzoj 2007)
Description
YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域。简单起见,可以将YT市看作一个
正方形,每一个区域也可看作一个正方形。从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路
(简称道路),每条双向道路连接主干道上两个相邻的交叉路口。下图为一张YT市的地图(n = 2),城市被划分为2
×2个区域,包括3×3个交叉路口和12条双向道路。 小Z作为该市的市长,他根据统计信息得到了每天上班高峰期
间YT市每条道路两个方向的人流量,即在高峰期间沿着该方向通过这条道路的人数。每一个交叉路口都有不同的海
拔高度值,YT市市民认为爬坡是一件非常累的事情,每向上爬h的高度,就需要消耗h的体力。如果是下坡的话,则
不需要耗费体力。因此如果一段道路的终点海拔减去起点海拔的值为h(注意h可能是负数),那么一个人经过这段路
所消耗的体力是max{0, h}(这里max{a, b}表示取a, b两个值中的较大值)。 小Z还测量得到这个城市西北角的交
叉路口海拔为0,东南角的交叉路口海拔为1(如上图所示),但其它交叉路口的海拔高度都无法得知。小Z想知道在
最理想的情况下(即你可以任意假设其他路口的海拔高度),每天上班高峰期间所有人爬坡所消耗的总体力和的最
小值。
Input
第一行包含一个整数n,含义如上文所示。接下来4n(n + 1)行,每行包含一个非负整数分别表示每一条道路每一个
方向的人流量信息。输入顺序:n(n + 1)个数表示所有从西到东方向的人流量,然后n(n + 1)个数表示所有从北到
南方向的人流量,n(n + 1)个数表示所有从东到西方向的人流量,最后是n(n + 1)个数表示所有从南到北方向的人
流量。对于每一个方向,输入顺序按照起点由北向南,若南北方向相同时由西到东的顺序给出(参见样例输入)。
Output
仅包含一个数,表示在最理想情况下每天上班高峰期间所有人爬坡所消耗的总体力和(即总体力和的最小值),结
果四舍五入到整数。
Sample Input
1
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
Sample Output
3
/* 首先可以大胆推一波结论:海拔高度非0即1。 那么即相当于找一条分界线,把图分成两部分,平面图最小割! 但是这个图是有向图,所以正反都要建边,在纸上画一画就是到怎么搞了。 */ #include<iostream> #include<cstdio> #include<queue> #include<cstring> #define N 1000010 using namespace std; int head[N],dis[N],vis[N],n,S,T,cnt; struct node{int v,w,pre;}e[N*4]; struct Node{ int pos,dis; bool operator< (const Node&x) const{ return dis>x.dis; } };priority_queue<Node> q; void add(int u,int v,int w){ e[++cnt].v=v;e[cnt].w=w;e[cnt].pre=head[u];head[u]=cnt; } int Dij(){ memset(dis,127/3,sizeof(dis)); q.push((Node){S,0});dis[S]=0; while(!q.empty()){ int u=q.top().pos;q.pop(); if(vis[u]) continue; vis[u]=1; for(int i=head[u];i;i=e[i].pre) if(dis[e[i].v]>dis[u]+e[i].w){ dis[e[i].v]=dis[u]+e[i].w; q.push((Node){e[i].v,dis[e[i].v]}); } } return dis[T]; } int id(int x,int y){ if(!y||x==n+1) return S; if(!x||y==n+1) return T; return (x-1)*n+y; } int main(){ scanf("%d",&n); S=0;T=n*n+1; int x; for(int i=0;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&x),add(id(i+1,j),id(i,j),x); for(int i=1;i<=n;i++) for(int j=0;j<=n;j++) scanf("%d",&x),add(id(i,j),id(i,j+1),x); for(int i=0;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&x),add(id(i,j),id(i+1,j),x); for(int i=1;i<=n;i++) for(int j=0;j<=n;j++) scanf("%d",&x),add(id(i,j+1),id(i,j),x); printf("%d",Dij()); return 0; }