当前位置: 代码迷 >> 综合 >> BZOJ 2007 [NOI2010 D1T3] 海拔
  详细解决方案

BZOJ 2007 [NOI2010 D1T3] 海拔

热度:0   发布时间:2024-01-19 02:14:39.0

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

Sample Output

3

【样例说明】
样例数据见下图。


最理想情况下所有点的海拔如上图所示。
对于100%的数据:1 ≤ n ≤ 500,0 ≤ 流量 ≤ 1,000,000且所有流量均为整数。

HINT

Source

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

平面图转对偶图+dijkstra~

因为左上角0右下角1,所以每个点不是0就是1,而显然从0过渡到1才是最优解。那么问题就转化为了寻找01分界线。最小割。

但是发现最小割过不了,边太多。所以用和BZOJ 1001一样的方法平面图转对偶图,再跑最短路。

另:这道题卡SPFA……现学了dijkstra+堆优化的做法,感觉和SPFA并没有什么差别。


#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
#define d(u,v) ((u-1)*n+v) int n,x,fi[250005],ne[1010001],w[1010001],v[1010001],cnt,dis[250005];struct node{int dis,x;bool operator <(const node &u) const{return u.dis<dis;}
}tmp;priority_queue<node> q;int read()
{int x=0,f=1;char ch=getchar();while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;
}void add(int u,int vv,int val)
{w[++cnt]=vv;ne[cnt]=fi[u];fi[u]=cnt;v[cnt]=val;
}void dij()
{memset(dis,127/3,sizeof(dis));tmp.dis=dis[0]=0;tmp.x=0;q.push(tmp);while(!q.empty()){int xx=q.top().x,dd=q.top().dis;q.pop();if(dd!=dis[xx]) continue;for(int i=fi[xx];i;i=ne[i])if(dis[w[i]]>dis[xx]+v[i]){dis[w[i]]=dis[xx]+v[i];tmp.dis=dis[w[i]];tmp.x=w[i];q.push(tmp);}}
}int main()
{n=read();for(int i=0;i<=n;i++)for(int j=1;j<=n;j++){x=read();if(!i) add(0,d(1,j),x);else if(i==n) add(d(i,j),n*n+1,x);else add(d(i,j),d(i+1,j),x);}for(int i=1;i<=n;i++)for(int j=0;j<=n;j++){x=read();if(!j) add(d(i,1),n*n+1,x);else if(j==n) add(0,d(i,j),x);else add(d(i,j+1),d(i,j),x);}for(int i=0;i<=n;i++)for(int j=1;j<=n;j++){x=read();if(!i) add(d(1,j),0,x);else if(i==n) add(n*n+1,d(i,j),x);else add(d(i+1,j),d(i,j),x);}for(int i=1;i<=n;i++)for(int j=0;j<=n;j++){x=read();if(!j) add(n*n+1,d(i,1),x);else if(j==n) add(d(i,j),0,x);else add(d(i,j),d(i,j+1),x);}dij();printf("%d\n",dis[n*n+1]);return 0;
}


  相关解决方案