【题解】 P6062 [USACO05JAN]Muddy Fields G
CG__HeavenHealer · · 题解
【题解】 P6062 [USACO05JAN]Muddy Fields G
题意
有一个
解法
因为木板在一行或一列上可能不能完全覆盖,所以我们可以把整个图的行、列重新定义一下:在原图中,每一行连续的泥地标记为同一行,列同理,所以我们可以得到这样一张新的图:(以样例为例)
这部分可以这样处理:
for (ri i = 1; i <= n; i++)
for (ri j = 1; j <= m; j++) {
if (s[i][j] == '.') continue;
if (j == 1 || s[i][j - 1] == '.') cntx++;
a[i][j].x = cntx;
}
for (ri j = 1; j <= m; j++)
for (ri i = 1; i <= n; i++) {
if (s[i][j] == '.') continue;
if (i == 1 || s[i - 1][j] == '.') cnty++;
a[i][j].y = cnty;
}
// 要注意区分好行和列,不要弄混
要求的就是怎样用最少的木板覆盖整张图
我们可以对行和列连边建出一张图,因为行和列无关,所以其内部不会连边,即建出来的图一定是二分图。建好的图如图:
要令整张图被覆盖,就要让每块泥地都被覆盖。以第一张图
这不就是二分图最小点覆盖吗?
而由 Konig 定理可知:二分图最小点覆盖顶点数等于最大匹配
这样,问题就迎刃而解了:把每块泥地的行向列连边,求最大匹配即可
匈牙利应该在座都会吧
Code:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ri register int
const int N = 1010;
inline int read() {
ri x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return f * x;
}
struct Edge {
int to, nxt;
} e[N << 1];
int head[N], cnt;
inline void add(int u, int v) {
e[++cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int match[N];
bool vis[N];
bool dfs(int u) {
for (ri i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (vis[v]) continue;
vis[v] = true;
if (!match[v] || dfs(match[v])) {
match[v] = u;
return true;
}
}
return false;
}
char s[N][N];
struct node {
int x, y;
} a[N][N];
signed main() {
int n = read(), m = read(), ans = 0;
int cntx = 0, cnty = 0;
for (ri i = 1; i <= n; i++) scanf("%s", s[i] + 1);
for (ri i = 1; i <= n; i++)
for (ri j = 1; j <= m; j++) {
if (s[i][j] == '.') continue;
if (j == 1 || s[i][j - 1] == '.') cntx++;
a[i][j].x = cntx;
}
for (ri j = 1; j <= m; j++)
for (ri i = 1; i <= n; i++) {
if (s[i][j] == '.') continue;
if (i == 1 || s[i - 1][j] == '.') cnty++;
a[i][j].y = cnty;
}
for (ri i = 1; i <= n; i++)
for (ri j = 1; j <= m; j++)
if (s[i][j] == '*') add(a[i][j].x, a[i][j].y);
// for (ri i = 1; i <= n; i++)
// for (ri j = 1; j <= m; j++)
// printf("i=%lld,j=%lld:x-%lld,y-%lld\n", i, j, a[i][j].x,
// a[i][j].y);
for (ri i = 1; i <= cntx; i++) {
memset(vis, false, sizeof(vis));
ans += dfs(i);
}
cout << ans << endl;
return 0;
}