POJ 1325 Machine Schedule(最小点覆盖)
解题思路
对原图做预处理,给横向的连通块和纵向的连通块编号,那么对于这个连通块内的点就有两个选择(x,y),这个点只有被其中一个覆盖就能被覆盖。所以结果就是求所有x->y的最大匹配,为什么呢?假设有一条边x_i -> x_j,如果两点不能匹配,说明其中一个已经匹配上了,根据前面所说的,只要被两个点中的一个覆盖就能覆盖一个点。假设两点能匹配,那么就说明有的点没有被覆盖,所以要求最大匹配。
代码
const int maxn = 1e2+10;
const int maxm = 1e4+10;
int r, c, x, y, nx[maxn][maxn], ny[maxn][maxn];
int mp[3000][3000], vis[maxm], match[maxm];
char g[maxn][maxn];
int find(int xx) {
for (int i = 1; i<=y; ++i)
if (mp[xx][i] && !vis[i]) {
vis[i] = true;
if (!match[i] || find(match[i])) {
match[i] = xx; return 1;
}
}
return 0;
}
int main() {
cin >> r >> c;
for (int i = 1; i<=r; ++i) scanf("%s", g[i]+1);
for (int i = 1; i<=r; ++i)
for (int j = 1; j<=c; ++j)
if (g[i][j]=='*') {
++x;
while(g[i][j]=='*') {
nx[i][j] = x; ++j;
//这里会跳过一个点,不过那个肯定不是结尾就是'.',不影响
}
}
for (int i = 1; i<=c; ++i)
for (int j = 1; j<=r; ++j)
if (g[j][i]=='*') {
++y;
while(g[j][i]=='*') {
ny[j][i] = y; ++j;
//这里会跳过一个点,不过那个肯定不是结尾就是'.',不影响
}
}
for (int i = 1; i<=r; ++i)
for (int j = 1; j<=c; ++j)
if (g[i][j]=='*') mp[nx[i][j]][ny[i][j]] = 1;
int ans = 0;
for (int i = 1; i<=x; ++i) {
zero(vis);
if (find(i)) ++ans;
}
cout << ans << endl;
return 0;
}