题目大意
给定 $n \times m$ 的网格图,每个格子有一个高度 $h_{i, j}$。给一个格子的高度增加 $x$ 需要花费 $x$ 的代价。你要调整某些格子的高度,使得不存在高度单调不下降的,从起点到终点的路径。求需要花费的最小代价。
数据范围:$n, m \le 50$。
思路分析
看到 “不存在……的路径” 就想到最小割建图。但是直接对于每对相邻的格子建图不可行,因为一个格子高度的增加可能同时影响到与之相邻的几个格子。也就是说,如果需要使格子 $x$ 的高度比格子 $y_1, y_2, \cdots, y_k$ 大,所需要的代价不是 $\sum_{i = 1}^{k} \text{cost}(x, y_i)$,而是 $\max_{i = 1}^{k} \text{cost}(x, y_i)$,其中 $\text{cost}(x, y)$ 表示格子 $x$ 要比格子 $y$ 高需要花费的代价,也就是 $\max{0, h(y) - h(x) + 1}$。
所以,我们对于每个格子拆点,一起考虑它周围一圈的格子。例如对于下图中的格子:
需要建如下结构的图:
另外注意一些小细节:
- $-1$ 最好提前判掉,否则可能会引起不必要的麻烦。
- 起点和终点的建图需要特判,因为题意要求起点和终点的高度不能变化。
代码实现
本菜鸡的 Dinic 跑不过(明明各种优化都加满了啊 QAQ),所以使用了 ISAP 来实现最大流。
1 |
|
2 |
|
3 |
|
4 | |
5 |
|
6 |
|
7 |
|
8 |
|
9 | using namespace std; |
10 | |
11 | const int maxn = 12500, maxm = 4e4, inf = 1e9 + 1; |
12 | const int dx[] = { -1, 0, 1, 0 }, dy[] = { 0, 1, 0, -1 }; |
13 | int T, n, m, Rr, Cr, Rt, Ct, s, t, mx, a[maxn + 3], b[5], c; |
14 | int tot, ter[maxm + 3], wei[maxm + 3], nxt[maxm + 3], lnk[maxn + 3], dep[maxn + 3], gap[maxn + 3], cur[maxn + 3]; |
15 | queue<int> Q; |
16 | |
17 | inline int id(const int &x, const int &y) { |
18 | return (x - 1) * m + y; |
19 | } |
20 | |
21 | inline int adj(int x) { |
22 | return x & 1 ? x + 1 : x - 1; |
23 | } |
24 | |
25 | bool check(int Rr, int Cr, int Rt, int Ct) { |
26 | if (Rr == Rt && Cr == Ct) return true; |
27 | if (abs(Rr - Rt) + abs(Cr - Ct) > 1) return false; |
28 | return a[id(Rr, Cr)] >= a[id(Rt, Ct)]; |
29 | } |
30 | |
31 | bool comp(int x, int y) { |
32 | return a[x] > a[y]; |
33 | } |
34 | |
35 | void add_edge(int u, int v, int w) { |
36 | ter[++tot] = v, wei[tot] = w; |
37 | nxt[tot] = lnk[u], lnk[u] = tot; |
38 | } |
39 | |
40 | void add_fedge(int u, int v, int w) { |
41 | add_edge(u, v, w), add_edge(v, u, 0); |
42 | } |
43 | |
44 | void ibfs(int s, int t) { |
45 | memset(gap, 0, sizeof(gap)); |
46 | memset(dep, 0, sizeof(dep)); |
47 | dep[s] = 1, Q.push(s); |
48 | for (int u; !Q.empty(); ) { |
49 | u = Q.front(), Q.pop(); |
50 | gap[dep[u]]++; |
51 | for (int i = lnk[u], v, w; i; i = nxt[i]) { |
52 | v = ter[i], w = wei[adj(i)]; |
53 | if (dep[v]) continue; |
54 | dep[v] = dep[u] + 1, Q.push(v); |
55 | } |
56 | } |
57 | } |
58 | |
59 | int dfs(int u, int flow, int s, int t) { |
60 | if (u == t) return flow; |
61 | int ans = 0; |
62 | for (int i = cur[u], v, w, x; i && ans < flow; i = nxt[i]) { |
63 | v = ter[i], w = wei[i]; |
64 | if (w && dep[v] == dep[u] - 1) { |
65 | cur[u] = i, x = dfs(v, min(flow - ans, w), s, t); |
66 | ans += x, wei[i] -= x, wei[adj(i)] += x; |
67 | } |
68 | } |
69 | if (ans < flow) { |
70 | if (!--gap[dep[u]]) dep[s] = mx + 1; |
71 | ++gap[++dep[u]], cur[u] = lnk[u]; |
72 | } |
73 | return ans; |
74 | } |
75 | |
76 | int flow(int s, int t) { |
77 | ibfs(t, s); |
78 | int ans = 0; |
79 | memcpy(cur, lnk, sizeof(lnk)); |
80 | while (dep[s] <= mx) { |
81 | ans += dfs(s, inf, s, t); |
82 | } |
83 | return ans; |
84 | } |
85 | |
86 | int main() { |
87 | scanf("%d", &T); |
88 | while (T--) { |
89 | scanf("%d %d", &n, &m); |
90 | scanf("%d %d %d %d", &Rr, &Cr, &Rt, &Ct); |
91 | for (int i = 1; i <= n; i++) { |
92 | for (int j = 1; j <= m; j++) { |
93 | scanf("%d", &a[id(i, j)]); |
94 | } |
95 | } |
96 | if (check(Rr, Cr, Rt, Ct)) { |
97 | puts("-1"); |
98 | continue; |
99 | } |
100 | s = id(Rr, Cr), t = id(Rt, Ct), mx = id(n, m); |
101 | tot = 0, memset(lnk, 0, sizeof(lnk)); |
102 | for (int i = 1; i <= n; i++) { |
103 | for (int j = 1; j <= m; j++) { |
104 | if (id(i, j) == s || id(i, j) == t) { |
105 | for (int k = 0, x, y; k < 4; k++) { |
106 | x = i + dx[k], y = j + dy[k]; |
107 | if (x < 1 || x > n || y < 1 || y > m) continue; |
108 | if (a[id(x, y)] >= a[id(i, j)]) { |
109 | add_fedge(id(x, y), id(i, j), inf); |
110 | } else { |
111 | add_fedge(id(x, y), id(i, j), 0); |
112 | } |
113 | } |
114 | continue; |
115 | } |
116 | c = 0; |
117 | for (int k = 0, x, y; k < 4; k++) { |
118 | x = i + dx[k], y = j + dy[k]; |
119 | if (x < 1 || x > n || y < 1 || y > m) continue; |
120 | if (a[id(x, y)] >= a[id(i, j)]) b[++c] = id(x, y); |
121 | } |
122 | sort(b + 1, b + c + 1, comp); |
123 | int tmp = id(i, j); |
124 | for (int k = 1; k <= c; k++) { |
125 | ++mx, add_fedge(b[k], mx, inf); |
126 | add_fedge(mx, tmp, a[b[k]] - a[id(i, j)] + 1), tmp = mx; |
127 | } |
128 | } |
129 | } |
130 | printf("%d\n", flow(s, t)); |
131 | } |
132 | return 0; |
133 | } |