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;
}
原文地址:https://www.cnblogs.com/shuitiangong/p/13526919.html