Description
给定一张 (n imes m (n,m le 50)) 网格图,上面有些格子是不可经过的点,要求用最少条路径去覆盖所有可以经过的点,移动只能像马一样行走,走 (r imes 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;
}