1 2 3 4

poj 2226 二分图最小顶点覆盖

传送门 : http://poj.org/problem?id=2226

这个题需要的知识

1  二分图的最大匹配(网络流,或者匈牙利)

2  二分图的最小顶点覆盖等于最大匹配

左边顶点是行编号,右边顶点是列编号,每个边是一个泥坑。顶点覆盖边,就是木板覆盖泥坑。

具体看代码吧,横着扫一遍竖着再扫一遍

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 1000;
char map[maxn][maxn];
vector<int>G[maxn];
void add(int x, int y) {
	G[x].push_back(y);
}

int n, m;
int vis[maxn];
int match[maxn];
int id1[maxn][maxn], id2[maxn][maxn];

int dfs(int x) {
	for (int i = 0; i < G[x].size(); i++){
		int p = G[x][i];
		if (!vis[p]) {
			vis[p] = 1;
			if (!match[p] || dfs(match[p])) {
				match[p] = x;
				return 1;
			}
		}
		
	}
	return 0;
}




int main() {
	scanf("%d%d", &n, &m);
	for (int i = 0; i < n; i++) {
		scanf("%s", map[i]);
	}
	int cnt = 0;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (map[i][j] == '*') {
				if (j == 0) id1[i][j] = ++cnt;
				else {
					if (id1[i][j - 1] == 0) id1[i][j] = ++cnt;
					else id1[i][j] = id1[i][j - 1];
				}
			}
		}
	}


	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			if (map[j][i] == '*') {
				if (j == 0) id2[j][i] = ++cnt;
				else {
					if (id2[j - 1][i] == 0) id2[j][i] = ++cnt;
					else id2[j][i] = id2[j - 1][i];
				}
			}
		}
	}

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (map[i][j] == '*') {
				add(id1[i][j], id2[i][j]);
				add(id2[i][j], id1[i][j]);
			}
		}
	}
	int ans = 0;
	
	for (int i = 1; i <= cnt; i++) {
		memset(vis, 0, sizeof(vis));
		if (dfs(i)) ans++;
	}
	printf("%d\n", ans / 2);
	return 0;
}

  

posted @ 2020-07-09 18:03  Lesning  阅读(203)  评论(0编辑  收藏  举报