[P2172] 部落戰爭 - 最小路徑覆蓋
阿新 • • 發佈:2020-12-06
Description
給定一張 \(n \times m (n,m \le 50)\) 網格圖,上面有些格子是不可經過的點,要求用最少條路徑去覆蓋所有可以經過的點,移動只能像馬一樣行走,走 \(r \times c\),但只能向下走。
Solution
最小路徑覆蓋轉化為最大獨立集或二分圖匹配問題。
每個點建模成兩個點 \(i,i'\),分別放置在二分圖的兩部。
可以認為一開始所有的路徑相互獨立。
每找到一條匹配邊,相當於把兩條路徑連線成了同一條路徑。
#include <bits/stdc++.h> using namespace std; const int N = 16384, MAXN = 262144; #define reset(x) memset(x, 0, sizeof x) struct graph { int n, m, M, S, T, head[N], cur[N], dep[N], gap[N], q[N]; long long ans; struct ed { int to, nxt, val; } edge[MAXN]; void init(int n0, int m0, int S0, int T0) { n = n0, m = m0, S = S0, T = T0, M = 1, reset(gap); reset(head), reset(cur), reset(dep), reset(q); } void _make(int u, int v, int w) { edge[++M] = (ed){v, head[u], w}, head[u] = M; } void make(int u, int v, int w) { _make(u, v, w); _make(v, u, 0); } int dfs(int u, int mx) { if (u == T) return mx; int num = 0, f; for (int &i = cur[u], v; i; i = edge[i].nxt) if (dep[v = edge[i].to] == dep[u] - 1 && (f = edge[i].val)) if (edge[i].val -= (f = dfs(v, min(mx - num, f))), edge[i ^ 1].val += f, (num += f) == mx) return num; if (!--gap[dep[u]++]) dep[S] = n + 1; return ++gap[dep[u]], cur[u] = head[u], num; } void solve() { for (int i = 1; i <= n; ++i) cur[i] = head[i]; ans = 0; for (gap[0] = n; dep[S] <= n; ans += dfs(S, 0x7fffffff)) ; } } g; char s[55][55]; signed main() { int n, m, r, c; cin >> n >> m >> r >> c; for (int i = 1; i <= n; i++) { cin >> s[i] + 1; } int dx[] = {r, r, c, c, }; int dy[] = {c, -c, r, -r}; auto id_source = [&](void) -> int { return 1; }; auto id_target = [&](void) -> int { return 2; }; auto id_vertex_in = [&](int i, int j) -> int { return 2 + (i - 1) * m + j; }; auto id_vertex_out = [&](int i, int j) -> int { return 2 + n * m + (i - 1) * m + j; }; auto check = [&](int i, int j) -> bool { return i >= 1 && j >= 1 && i <= n && j <= m; }; int total = 0; g.init(2 * n * m + 2, 0, id_source(), id_target()); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { for (int k = 0; k < 4; k++) { int ni = i + dx[k]; int nj = j + dy[k]; if (check(ni, nj)) { g.make(id_vertex_in(i, j), id_vertex_out(ni, nj), 1); } } if (s[i][j] == '.') { g.make(id_source(), id_vertex_in(i, j), 1); g.make(id_vertex_out(i, j), id_target(), 1); ++total; } } } g.solve(); cout << total - g.ans << endl; }