BZOJ2007 [Noi2010]海拔
问题描述
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
输入文件 altitude.in 第一行包含一个整数 n,含义如上文所示。接下来 4n(n + 1)行,每行包含一个非负整数分别表示每一条道路每一个方向的人流量信息。输入顺序:n(n + 1)个数表示所有从西到东方向的人流量,然
后 n(n + 1)个数表示所有从北到南方向的人流量,n(n + 1)个数表示所有从东到西方向的人流量,最后是 n(n + 1)个数表示所有从南到北方向的人流量。对于每一个方向,输入顺序按照起点由北向南,若南北方向相同时由西到东的顺序给出(参见样例输入)。
Output
输出文件 altitude.out 仅包含一个数,表示在最理想情况下每天上班高峰期间所有人爬坡所消耗的总体力和(即总体力和的最小值),结果四舍五入到整数。
Sample Input
1
1
2
3
4
5
6
7
8
Sample Output
3
样例说明
样例数据见下图。
最理想情况下所有点的海拔如上图所示。
数据规模
对于 20%的数据:n ≤ 3;
对于 50%的数据:n ≤ 15;
对于 80%的数据:n ≤ 40;
对于 100%的数据:1 ≤ n ≤ 500,0 ≤为整数。流量
提示
海拔高度不一定是整数。
正解:对偶图+dijkstra
解题报告:
今天考试T1。
这道题迷惑性太强了,还故意给了一个提示,其实就是误导,本来了我大胆猜测了要么是1要么是0,结果被这个提示吓住了。但我看到保留到整数,觉得很蹊跷,如果是小数的话保留到整数的话不是很鸡肋?于是还是保留了猜想,结果多疑的我没有选择写正解,就用这个结论写了个暴力,考完都说结论正确...
显然我们只需要考虑0和1的分界线在何处即可。当然我们需要找到一些边集,把图分成两半,且权值和最小。这不就是最小割吗...所以直接把原图转成对偶图,然后跑dijkstra。
注意连边的时候考虑方向,我们不妨假定对偶图边经过的方向,左边海拔为0,右边海拔为1,然后只要算0到1的,所以就是正方向的权值。所以我们只需要把方向相反的两条边在对偶图中也构出方向相反的即可。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long LL; 15 #define RG register 16 const int MAXN = 1000011; 17 const int MAXM = 2000011; 18 const int inf = (1<<30); 19 int n,ecnt,s,t; 20 int first[MAXN],to[MAXM],next[MAXM],w[MAXM]; 21 int dis[MAXN]; 22 struct node{ 23 int dis,x; 24 bool operator < (const node &a) const{ 25 return a.dis<dis; 26 } 27 }tmp; 28 priority_queue<node>Q; 29 30 inline int getint() 31 { 32 RG int w=0,q=0; RG char c=getchar(); 33 while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 34 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w; 35 } 36 37 inline void link(RG int x,RG int y,RG int z){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z; } 38 inline void link2(RG int x,RG int y,RG int z){ next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; w[ecnt]=z; } 39 inline void dijkstra(){ 40 for(int i=1;i<=t;i++) dis[i]=inf; 41 tmp.dis=dis[s]=0; tmp.x=s; Q.push(tmp); RG int ju,u; 42 while(!Q.empty()) { 43 u=Q.top().x; ju=Q.top().dis; Q.pop(); 44 if(ju==dis[u]) { 45 for(int i=first[u];i;i=next[i]) { 46 int v=to[i]; 47 if(dis[v]>dis[u]+w[i]) { 48 dis[v]=dis[u]+w[i]; 49 tmp.x=v; tmp.dis=dis[v]; 50 Q.push(tmp); 51 } 52 } 53 } 54 } 55 printf("%d",dis[t]); 56 } 57 58 inline void work(){ 59 n=getint(); s=n*n+1; t=s+1; RG int x; 60 //边的右边是海拔为1的,边的左边是海拔为0的,相当于在网格图中选一些边作为过渡边 61 //每行只有n个面,不是点! 62 for(RG int i=0;i<=n;i++) for(RG int j=1;j<=n;j++){ x=getint(); if(i==n) link(s,(i-1)*n+j,x); else if(i==0) link(j,t,x); else link(i*n+j,(i-1)*n+j,x); } 63 for(RG int i=1;i<=n;i++) for(RG int j=0;j<=n;j++){ x=getint(); if(j==0) link(s,(i-1)*n+j+1,x); else if(j==n) link(i*n,t,x); else link((i-1)*n+j,(i-1)*n+j+1,x); } 64 for(RG int i=0;i<=n;i++) for(RG int j=1;j<=n;j++){ x=getint(); if(i==n) link2(s,(i-1)*n+j,x); else if(i==0) link2(j,t,x); else link2(i*n+j,(i-1)*n+j,x); } 65 for(RG int i=1;i<=n;i++) for(RG int j=0;j<=n;j++){ x=getint(); if(j==0) link2(s,(i-1)*n+j+1,x); else if(j==n) link2(i*n,t,x); else link2((i-1)*n+j,(i-1)*n+j+1,x); } 66 dijkstra(); 67 } 68 69 int main() 70 { 71 work(); 72 return 0; 73 }