只要你跑的够快,锅就追不上你

0%

「Codechef SKIRES」Ski Resort(最小割)

题目大意

「Codechef SKIRES」Ski Resort

给定 $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

需要建如下结构的图:

图 2

另外注意一些小细节:

  • $-1$ 最好提前判掉,否则可能会引起不必要的麻烦。
  • 起点和终点的建图需要特判,因为题意要求起点和终点的高度不能变化。

代码实现

本菜鸡的 Dinic 跑不过(明明各种优化都加满了啊 QAQ),所以使用了 ISAP 来实现最大流。

1
#pragma GCC optimize(2)
2
#pragma GCC optimize(3)
3
#pragma GCC optimize("Ofast")
4
5
#include <cstdio>
6
#include <cstring>
7
#include <queue>
8
#include <algorithm>
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
}