二分匹配与最小点覆盖

先来看看2道最小点覆盖的裸题:

POJ3041:题意是给出一个N*N的矩阵,有些格子上有障碍,要求每次消除一行或者一列的障碍,最少消除多少次可以全部清除障碍。做法就是把行和列都看做点,然后障碍物(x,y)就可以看作是x点和y点的边。这样问题就转化成选择最少的边(x,y)使得所有的点都被覆盖。在二分图中,最小点覆盖数=最大匹配数。所以可以用匈牙利算法解决。

代码君:

View Code
 1 #include <cstdio>
 2 #include <vector>
 3 #include <cstring>
 4 using namespace std;
 5 
 6 const int maxn = 5555;
 7 int n, k, x, y, match[maxn];
 8 bool vis[maxn];
 9 vector<int> adj[maxn];
10 
11 void init() {
12    for (int i = 0; i < n; i++)
13        adj[i].clear();
14 }
15 
16 void addEdge(int u, int v) {
17     adj[u].push_back(v);
18 }
19 
20 bool find(int u) {
21     for (int i = 0; i < adj[u].size(); i++) {
22         int v = adj[u][i];
23         if (vis[v] == false) {
24             vis[v] = true;
25             if (match[v] == -1 || find(match[v])) {
26                 match[v] = u; return true;
27             }
28         }
29     }
30     return false;
31 }
32 
33 int solve() {
34     int result = 0;
35     memset(match, -1, sizeof(match));
36     for (int i = 1; i <= n; i++) {
37         memset(vis, false, sizeof(vis));
38         if (find(i)) result++;
39     }
40     return result;
41 }
42 
43 int main() {
44     while (~scanf("%d %d", &n, &k)) {
45         init();
46         for (int i = 1; i <= k; i++) {
47             scanf("%d %d", &x, &y);
48             addEdge(x, y);
49         }
50         printf("%d\n", solve());
51     }
52     return 0;
53 }

 POJ2226:题意是给出的是N*M的矩阵,同样是有障碍的格子,要求每次只能消除一行或一列中相邻的格子,最少消除多少次可以全部清除。做法和上面一题一样,只要加一点预处理:扫描一遍输入的矩阵,把每行和每列中相邻的障碍物看成一个点,记录一下,然后加边。这样就转化成了问题1。

代码君:

View Code
1 /*
2 先挖个坑
3 */

 

posted @ 2013-04-19 18:49  SDU_Phonism  阅读(168)  评论(0编辑  收藏  举报