【题目链接】
【思路要点】
- 若距离限制\(D≥N\),显然我们可以通过取每一条纵轴上的最小值求解,但我们也可以将每一条纵轴上的的权值首尾相连,形成一条有向链,将链首与链尾分别于源点和汇点用容量无穷的边相连,用最小割求解。
- 现在考虑距离限制\(D\),若将相邻纵轴上距离恰好为\(D\)的点从较后者向较前者连一条容量无穷的边,在最小割问题中就表示不能够同时不割去较后者之前的边和较前者之后的边,因此,我们保证了距离差\(≤D\)。
- 图中点数与边数均为\(O(P*Q*R)\)级别,时间复杂度\(O(Dinic(P*Q*R,P*Q*R))\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 45; const int MAXP = 70005; const int INF = 1e9; template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct edge {int dest, flow; unsigned home; }; int n, m, l, d, s, t, tot, flow; int point[MAXN][MAXN][MAXN], dist[MAXP]; unsigned curr[MAXP]; vector <edge> a[MAXP]; int dinic(int pos, int limit) { if (pos == t) return limit; int used = 0, tmp; for (unsigned &i = curr[pos]; i < a[pos].size(); i++) { if (a[pos][i].flow && dist[pos] + 1 == dist[a[pos][i].dest] && (tmp = dinic(a[pos][i].dest, min(limit - used, a[pos][i].flow)))) { used += tmp; a[pos][i].flow -= tmp; a[a[pos][i].dest][a[pos][i].home].flow += tmp; } if (used == limit) return used; } return used; } bool bfs() { static int q[MAXP]; static int l = 0, r = -1; for (int i = 0; i <= r; i++) dist[q[i]] = 0; l = 0, r = -1; q[++r] = s; dist[s] = 1; while (l <= r) { int tmp = q[l++]; for (unsigned i = 0; i < a[tmp].size(); i++) if (a[tmp][i].flow && dist[a[tmp][i].dest] == 0) { dist[a[tmp][i].dest] = dist[tmp] + 1; q[++r] = a[tmp][i].dest; } } return dist[t] != 0; } void addedge(int s, int t, int flow) { a[s].push_back((edge) {t, flow, a[t].size()}); a[t].push_back((edge) {s, 0, a[s].size() - 1}); } int main() { read(n), read(m), read(l); s = tot = 0; for (int k = 0; k <= l; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) point[k][i][j] = ++tot; t = ++tot; read(d); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { addedge(s, point[0][i][j], INF); addedge(point[l][i][j], t, INF); } for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (i != n) { int ti = i + 1; for (int k = d; k <= l; k++) { addedge(point[k][i][j], point[k - d][ti][j], INF); addedge(point[k][ti][j], point[k - d][i][j], INF); } } if (j != m) { int tj = j + 1; for (int k = d; k <= l; k++) { addedge(point[k][i][j], point[k - d][i][tj], INF); addedge(point[k][i][tj], point[k - d][i][j], INF); } } } for (int k = 1; k <= l; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { int x; read(x); addedge(point[k - 1][i][j], point[k][i][j], x); } while (bfs()) { memset(curr, 0, sizeof(curr)); flow += dinic(s, INF); } printf("%d\n", flow); return 0; }