题意:给定一个矩阵,其中有一些地方有水,用一些长度任意,宽度为1的木板盖住这些有水的地方,问至少需要几块板子。
分析:二分图最小点集覆盖。二分图建图方法如下,把每段连续的横向的水洼看成是一个X集合中的点,每段连续的纵向的水洼看成是Y集合中的点。矩阵每个有水单元看成是一个边,它连接了它所在的横向水洼在X集合中对应的点和它所在的纵向水洼在Y集合中对应的点。(对于一段连续的水洼,如果要铺木板,一定要铺得尽量长)这样最小点集覆盖的意义就变成了,矩阵中的每个有水的单元(二分图中的每条边)所在的横向和纵向的水洼(在X集合和Y集合中的两个端点)至少有一个被覆盖。求至少需要选几个点。

#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; #define maxr 55 #define maxc 55 #define maxx maxr * maxc / 2 #define maxy maxx struct Edge { int x, y; }edge[maxr][maxc]; int row, column; char map[maxr][maxc]; int xcount, ycount; bool visit[maxy]; int match[maxy]; bool g[maxx][maxy]; void input() { scanf("%d%d", &row, &column); for (int i = 0; i < row; i++) scanf("%s", map[i]); } void make() { xcount = 0; ycount = 0; for (int i = 0; i < row; i++) { int j = 0; while (j < column) { while (j < column && map[i][j] == '.') j++; if (j >= column) break; while (j < column && map[i][j] == '*') { edge[i][j].x = xcount; j++; } xcount++; } } for (int i = 0; i < column; i++) { int j = 0; while (j < row) { while (j < row && map[j][i] == '.') j++; if (j >= row) break; while (j < row && map[j][i] == '*') { edge[j][i].y = ycount; j++; } ycount++; } } for (int i = 0; i < row; i++) for (int j = 0; j < column; j++) if (map[i][j] == '*') { //printf("%d %d\n", edge[i][j].x, edge[i][j].y); g[edge[i][j].x][edge[i][j].y] = true; } } bool dfs(int k) { int t; for (int i = 0; i < ycount; i++) { if (g[k][i] && !visit[i]) { visit[i] = true; t = match[i]; match[i] = k; if (t == -1 || dfs(t)) return true; match[i] = t; } } return false; } int max_match() { int ans = 0; for (int i = 0; i < xcount; i++) { memset(visit, false, sizeof(visit)); if (dfs(i)) ans ++; } return ans; } int main() { //freopen("t.txt", "r", stdin); memset(g, 0, sizeof(g)); input(); make(); memset(match, -1, sizeof(match)); printf("%d\n", max_match()); return 0; }