2007: [Noi2010]海拔
Time Limit: 20 Sec Memory Limit: 552 MB
Submit: 1302 Solved: 612
[Submit][Status]
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
【样例说明】
样例数据见下图。
最理想情况下所有点的海拔如上图所示。
【数据规模】
对于20%的数据:n ≤ 3;
对于50%的数据:n ≤ 15;
对于80%的数据:n ≤ 40;
对于100%的数据:1 ≤ n ≤ 500,0 ≤ 流量 ≤ 1,000,000且所有流量均为整数。
HINT
Source
题解:
让这题给坑了--海拔不一定为整数……
其实每个点的海拔一定是0 or 1
证明:(声亦香)
如图,既然出发点海拔是0,终止点海拔是1,中间总有人流需要上坡,而我们的贪心思想是让尽量少的人流上坡,我们就要选择最少人流的道路,那么人流最少的道路就要让它的人流尽可能的上到与1齐平的位置,这样才能使后面更多的人流不需要上坡。如果当前决策的海拔在0到1之间,那么后面就会有人流在其基础上提升到1,而如果当前人流较小,总可以使当前海拔上到1,使决策更优。
这样问题就转化为,选取一些边,使得删掉它们后,s、t不连通(这是因为所有的人流都必须上升1),并且这些边的权值和最小。等等,这不就是最小割吗?
然后这又是平面图,因此构造其对偶图,求最短路……
这题80分还是很好拿的,spfa即可,满分算法即要求用heap+dijkstra,苦逼的p党啊,代码量骤增……
代码:
1 const maxn=2000000; 2 type node=record 3 from,go,next,w:longint; 4 end; 5 var i,j,n,cnt,tot,t,x,s,l,r,y:longint; 6 head,d,a,p:array[0..maxn] of longint; 7 v:array[0..maxn] of boolean; 8 e:array[0..maxn] of node; 9 num:array[0..600,0..600] of longint; 10 procedure insert(x,y,z:longint); 11 begin 12 inc(tot); 13 e[tot].from:=x;e[tot].go:=y;e[tot].w:=z;e[tot].next:=head[x];head[x]:=tot; 14 end; 15 procedure up(i:longint); 16 var t:longint; 17 begin 18 while (i>1) and (d[a[i]]<d[a[i>>1]]) do 19 begin 20 t:=a[i];a[i]:=a[i>>1];a[i>>1]:=t; 21 p[a[i]]:=i;p[a[i>>1]]:=i>>1; 22 i:=i>>1; 23 end; 24 end; 25 procedure down(i:longint); 26 var t,j:longint; 27 begin 28 j:=i<<1; 29 if (j<cnt) and (d[a[j+1]]<d[a[j]]) then inc(j); 30 while (j<=cnt) and (d[a[j]]<d[a[i]]) do 31 begin 32 t:=a[i];a[i]:=a[j];a[j]:=t; 33 p[a[i]]:=i;p[a[j]]:=j; 34 i:=j;j:=j<<1; 35 if (j<cnt) and (d[a[j+1]]<d[a[j]]) then inc(j); 36 end; 37 end; 38 procedure dijkstra; 39 begin 40 fillchar(d,sizeof(d),60); 41 fillchar(v,sizeof(v),false); 42 d[s]:=0;cnt:=0; 43 for i:=0 to n*n+1 do begin inc(cnt);a[cnt]:=i;p[i]:=cnt;up(cnt);end; 44 for j:=1 to n*n+1 do 45 begin 46 x:=a[1];a[1]:=a[cnt];dec(cnt);down(1); 47 v[x]:=true; 48 i:=head[x]; 49 while i<>0 do 50 begin 51 y:=e[i].go; 52 if not(v[y]) and (d[x]+e[i].w<d[y]) then 53 begin 54 d[y]:=d[x]+e[i].w; 55 up(p[y]); 56 end; 57 i:=e[i].next; 58 end; 59 end; 60 end; 61 62 procedure init; 63 begin 64 readln(n);s:=0;t:=n*n+1; 65 for i:=1 to n do for j:=1 to n do num[i,j]:=(i-1)*n+j; 66 for i:=1 to n+1 do 67 for j:=1 to n do 68 begin 69 readln(x); 70 if i=1 then insert(num[i,j],t,x) 71 else if i=n+1 then insert(s,num[i-1,j],x) 72 else insert(num[i,j],num[i-1,j],x); 73 end; 74 for i:=1 to n do 75 for j:=1 to n+1 do 76 begin 77 readln(x); 78 if j=1 then insert(s,num[i,j],x) 79 else if j=n+1 then insert(num[i,j-1],t,x) 80 else insert(num[i,j-1],num[i,j],x); 81 end; 82 for i:=1 to n+1 do 83 for j:=1 to n do 84 begin 85 readln(x); 86 if i=1 then insert(t,num[i,j],x) 87 else if i=n+1 then insert(num[i-1,j],s,x) 88 else insert(num[i-1,j],num[i,j],x); 89 end; 90 for i:=1 to n do 91 for j:=1 to n+1 do 92 begin 93 readln(x); 94 if j=1 then insert(num[i,j],s,x) 95 else if j=n+1 then insert(t,num[i,j-1],x) 96 else insert(num[i,j],num[i,j-1],x); 97 end; 98 end; 99 procedure main; 100 begin 101 dijkstra; 102 writeln(d[t]); 103 end; 104 begin 105 assign(input,‘input.txt‘);assign(output,‘output.txt‘); 106 reset(input);rewrite(output); 107 init; 108 main; 109 close(input);close(output); 110 end.
NOI2010海拔