2007: [Noi2010]海拔

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且所有流量均为整数。

一不小心就看到了是最小割233,然后就想到了最小割构图

因为左上角是0右下角是1,所以我们海拔肯定是0或者1,于是最小割就很明显了,就是他给你的这张图,左上角为源右下角为汇

数据太大所以我们又只能换成对偶图最短路了,可以参考bzoj1001狼与兔子,不过那是无向图,这个是有向图

于是右→下,下→左,左→上,上→右(还成环了233),跑一遍右上到左下的最短路就行了,直接SPFA有两个点过不去,所以我加了heap

  1 const
  2     maxn=510;
  3     inf=1000000000;
  4 var
  5     first:array[0..maxn*maxn]of longint;
  6     next,last,w:array[0..maxn*maxn*4]of longint;
  7     n,tot:longint;
  8  
  9 function calc(x,y:longint):longint;
 10 begin
 11     if (x=0) or (y=n+1) then exit(0);
 12     if (x=n+1) or (y=0) then exit(n*n+1);
 13     exit((x-1)*n+y);
 14 end;
 15  
 16 procedure insert(x,y:longint);
 17 begin
 18     inc(tot);
 19     last[tot]:=y;
 20     next[tot]:=first[x];
 21     first[x]:=tot;
 22 end;
 23  
 24 var
 25     q,h,dis:array[0..maxn*maxn]of longint;
 26     flag:array[0..maxn*maxn]of boolean;
 27     r:longint;
 28  
 29 procedure swap(var x,y:longint);
 30 var
 31     t:longint;
 32 begin
 33     t:=x;x:=y;y:=t;
 34 end;
 35  
 36 procedure up(x:longint);
 37 var
 38     i:longint;
 39 begin
 40     while x>1 do
 41         begin
 42             i:=x>>1;
 43             if dis[q[x]]<dis[q[i]] then
 44                 begin
 45                     swap(q[x],q[i]);
 46                     h[q[x]]:=x;h[q[i]]:=i;
 47                     x:=i;
 48                 end
 49             else exit;
 50         end;
 51 end;
 52  
 53 procedure down(x:longint);
 54 var
 55     i:longint;
 56 begin
 57     i:=x<<1;
 58     while i<=r do
 59         begin
 60             if (i<r) and (dis[q[i+1]]<dis[q[i]]) then inc(i);
 61             if dis[q[i]]<dis[q[x]] then
 62                 begin
 63                     swap(q[i],q[x]);
 64                     h[q[x]]:=x;h[q[i]]:=i;
 65                     x:=i;i:=x<<1;
 66                 end
 67             else exit;
 68         end;
 69 end;
 70  
 71 procedure delete;
 72 begin
 73     swap(q[1],q[r]);
 74     h[q[1]]:=1;
 75     dec(r);
 76     down(1);
 77 end;
 78  
 79 procedure spfa;
 80 var
 81     i:longint;
 82 begin
 83     r:=1;q[1]:=0;flag[0]:=true;h[0]:=1;
 84     for i:=1 to n*n+1 do dis[i]:=inf;
 85     while r>0 do
 86         begin
 87             if q[1]=n*n+1 then break;
 88             i:=first[q[1]];
 89             while i<>0 do
 90                 begin
 91                     if dis[q[1]]+w[i]<dis[last[i]] then
 92                     begin
 93                         if not flag[last[i]] then
 94                         begin
 95                             inc(r);q[r]:=last[i];h[last[i]]:=r;
 96                             flag[last[i]]:=true;
 97                         end;
 98                         dis[last[i]]:=dis[q[1]]+w[i];up(h[last[i]]);
 99                     end;
100                     i:=next[i];
101                 end;
102             flag[q[1]]:=false;delete;
103         end;
104 end;
105  
106 procedure main;
107 var
108     i,j:longint;
109 begin
110     read(n);
111     for i:=1 to 4*n*(n+1) do read(w[i]);
112     for i:=0 to n do
113         for j:=1 to n do
114             insert(calc(i,j),calc(i+1,j));
115     for i:=1 to n do
116         for j:=0 to n do
117             insert(calc(i,j+1),calc(i,j));
118     for i:=0 to n do
119         for j:=1 to n do
120             insert(calc(i+1,j),calc(i,j));
121     for i:=1 to n do
122         for j:=0 to n do
123             insert(calc(i,j),calc(i,j+1));
124     spfa;
125     writeln(dis[n*n+1]);
126 end;
127  
128 begin
129     main;
130 end.
View Code
原文地址:https://www.cnblogs.com/Randolph87/p/3792447.html