传送门 : 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 ", ans / 2); return 0; }