先来看看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 */