POJ 3041 Asteroids (二分图最小点覆盖)

题目链接:http://poj.org/problem?id=3041

在一个n*n的地图中,有m和障碍物,你每一次可以消除一行或者一列的障碍物,问你最少消除几次可以将障碍物全部清除。

用二分图将行(左边)和列(右边)用障碍物联系起来,比如(2,3)有个障碍物,那么左边的2和右边的3连边。边的个数就是障碍物的个数,点的个数就是次数,所以问题就变成了用少的点覆盖全部的边,也就是最小点覆盖问题。二分图中,最小点覆盖=最大匹配数。

 1 //最小点覆盖 = 最大匹配
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <vector>
 6 using namespace std;
 7 const int N = 505;
 8 struct Edge {
 9     int next , to;
10 }edge[N*N];
11 int head[N] , cnt , match[N];
12 bool vis[N];
13 
14 void init() {
15     memset(match , -1 , sizeof(match));
16     memset(head , -1 , sizeof(head));
17     memset(vis , false , sizeof(vis));
18     cnt = 0;
19 }
20 
21 inline void add(int u , int v) {
22     edge[cnt].next = head[u];
23     edge[cnt].to = v;
24     head[u] = cnt++;
25 }
26 
27 bool dfs(int u) {
28     for(int i = head[u] ; ~i ; i = edge[i].next) {
29         int v = edge[i].to;
30         if(!vis[v]) {
31             vis[v] = true;
32             if(match[v] == -1 || dfs(match[v])) {
33                 match[v] = u;
34                 return true;
35             }
36         }
37     }
38     return false;
39 }
40 
41 int hungry(int n) {
42     int res = 0;
43     for(int i = 1 ; i <= n ; ++i) {
44         memset(vis , false , sizeof(vis));
45         if(dfs(i))
46             res++;
47     }
48     return res;
49 }
50 
51 int main()
52 {
53     int n , m , u , v;
54     while(~scanf("%d %d" , &n , &m)) {
55         init();
56         for(int i = 0 ; i < m ; ++i) {
57             scanf("%d %d" , &u , &v);
58             add(u , v);
59         }
60         printf("%d
" , hungry(n));
61     }
62     return 0;
63 }
原文地址:https://www.cnblogs.com/Recoder/p/5671524.html