BZOJ 2007: [Noi2010]海拔

2007: [Noi2010]海拔

Time Limit: 20 Sec  Memory Limit: 552 MB
Submit: 2410  Solved: 1142
[Submit][Status][Discuss]

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

 
[Submit][Status][Discuss]

 

网络流 平面图最小割转对偶图最短路

 

有个性质,就是一定存在一组最优解,是一些点海拔为0,其余点海拔为1,且两类点各形成一个连通块,即产生代价的边为S到T的一个割边集合,代价即为流量和。

为了防止TLE,最好转对偶图做最短路,注意因为原本是有向边,所以转对偶图时也是有固定规则的有向边。

 

 

 1 #include <queue>
 2 #include <cstdio>
 3 
 4 inline int nextChar(void) {
 5     static const int siz = 1024;
 6     static char buf[siz];
 7     static char *hd = buf + siz;
 8     static char *tl = buf + siz;
 9     if (hd == tl)
10         fread(hd = buf, 1, siz, stdin);
11     return *hd++;
12 }
13 
14 inline int nextInt(void) {
15     register int ret = 0;
16     register int neg = false;
17     register int bit = nextChar();
18     for (; bit < 48; bit = nextChar())
19         if (bit == '-')neg ^= true;
20     for (; bit > 47; bit = nextChar())
21         ret = ret * 10 + bit - 48;
22     return neg ? -ret : ret;
23 }
24 
25 const int inf = 1e9;
26 const int siz = 10000005;
27 
28 int n;
29 int s, t;
30 int edges;
31 int hd[siz];
32 int to[siz];
33 int nt[siz];
34 int vl[siz];
35 int dis[siz];
36 
37 inline void add(int u, int v, int w) {
38     nt[edges] = hd[u]; 
39     to[edges] = v; 
40     vl[edges] = w; 
41     hd[u] = edges++;
42 }
43 
44 struct pair {
45     int x, y;
46     pair(void) {};
47     pair(int a, int b) :
48         x(a), y(b) {};
49     inline friend bool operator <
50     (const pair &a, const pair &b) {
51         return a.x > b.x;
52     }
53 };
54 
55 std::priority_queue<pair> h;
56 
57 inline int Dijkstra(void) {
58     h.push(pair(dis[s] = 0, s));
59     while (!h.empty()) {
60         pair p = h.top(); h.pop();
61         if (dis[p.y] != p.x)continue;
62         if (p.y == t)return dis[p.y];
63         for (int i = hd[p.y]; ~i; i = nt[i])
64             if (dis[to[i]] > dis[p.y] + vl[i])
65                 h.push(pair(dis[to[i]] = dis[p.y] + vl[i], to[i]));
66     }
67     return dis[t];
68 }
69 
70 inline int pos(int x, int y) {
71     if (x == 0 || y == n + 1)return s;
72     if (y == 0 || x == n + 1)return t;
73     return (x - 1) * n + y;
74 }
75 
76 signed main(void) {
77     n = nextInt();
78     s = 0, t = n * n + 1;
79     for (int i = s; i <= t; ++i)hd[i] = -1;
80     for (int i = s; i <= t; ++i)dis[i] = inf;
81     for (int i = 0; i <= n; ++i)
82         for (int j = 1; j <= n; ++j)
83             add(pos(i, j), pos(i + 1, j), nextInt());
84     for (int i = 1; i <= n; ++i)
85         for (int j = 0; j <= n; ++j)
86             add(pos(i, j + 1), pos(i, j), nextInt());
87     for (int i = 0; i <= n; ++i)
88         for (int j = 1; j <= n; ++j)
89             add(pos(i + 1, j), pos(i, j), nextInt());
90     for (int i = 1; i <= n; ++i)
91         for (int j = 0; j <= n; ++j)
92             add(pos(i, j), pos(i, j + 1), nextInt());
93     printf("%d\n", Dijkstra());
94 }

 

@Author: YouSiki

 

posted @ 2017-01-04 08:37  YouSiki  阅读(346)  评论(0编辑  收藏  举报