UVa 11419 我是SAM(最小点覆盖+路径输出)

https://vjudge.net/problem/UVA-11419

题意:一个网格里面有一些目标,可以从某一行,某一列发射一发子弹,可以打掉它;求最少的子弹,和在哪里打?

思路:

每个点的x坐标与y坐标相连,现在就是要找一个最小点覆盖,同时还要输出哪些点被覆盖了。

 1 #include <cstdio>  
 2 #include <cstring>  
 3 #include <vector>  
 4 #include <algorithm>  
 5 using namespace std;  
 6   
 7 const int maxn = 1000 + 5; // 单侧顶点的最大数目  
 8   
 9 // 二分图最大基数匹配  
10 struct BPM {  
11   int n, m;               // 左右顶点个数  
12   vector<int> G[maxn];    // 邻接表  
13   int left[maxn];         // left[i]为右边第i个点的匹配点编号,-1表示不存在  
14   bool T[maxn];           // T[i]为右边第i个点是否已标记  
15   
16   int right[maxn];        // 求最小覆盖用  
17   bool S[maxn];           // 求最小覆盖用  
18   
19   void init(int n, int m) {  
20     this->n = n;  
21     this->m = m;  
22     for(int i = 0; i < n; i++) G[i].clear();  
23   }  
24   
25   void AddEdge(int u, int v) {  
26     G[u].push_back(v);  
27   }  
28   
29   bool match(int u){  
30     S[u] = true;  
31     for(int i = 0; i < G[u].size(); i++) {  
32       int v = G[u][i];  
33       if (!T[v]){  
34         T[v] = true;  
35         if (left[v] == -1 || match(left[v])){  
36           left[v] = u;  
37           right[u] = v;  
38           return true;  
39         }  
40       }  
41     }  
42     return false;  
43   }  
44   
45   // 求最大匹配  
46   int solve() {  
47     memset(left, -1, sizeof(left));  
48     memset(right, -1, sizeof(right));  
49     int ans = 0;  
50     for(int u = 0; u < n; u++) { // 从左边结点u开始增广  
51       memset(S, 0, sizeof(S));  
52       memset(T, 0, sizeof(T));  
53       if(match(u)) ans++;  
54     }  
55     return ans;  
56   }  
57   
58   // 求最小覆盖。X和Y为最小覆盖中的点集  
59   int mincover(vector<int>& X, vector<int>& Y) {  
60     int ans = solve();  
61     memset(S, 0, sizeof(S));  
62     memset(T, 0, sizeof(T));  
63     for(int u = 0; u < n; u++)  
64       if(right[u] == -1) match(u); // 从所有X未盖点出发增广  
65     for(int u = 0; u < n; u++)  
66       if(!S[u]) X.push_back(u); // X中的未标记点  
67     for(int v = 0; v < m; v++)  
68       if(T[v]) Y.push_back(v);  // Y中的已标记点  
69    return ans;  
70   }  
71 };  
72   
73 BPM solver;  
74   
75 int R, C, N;  
76   
77 int main(){  
78   int kase = 0;  
79   while(scanf("%d%d%d", &R, &C, &N) == 3 && R && C && N) {  
80     solver.init(R, C);  
81     for(int i = 0; i < N; i++) {  
82       int r, c;  
83       scanf("%d%d", &r, &c); r--; c--;  
84       solver.AddEdge(r, c);  
85     }  
86     vector<int> X, Y;  
87     int ans = solver.mincover(X, Y);//把结果放在X,Y里面  
88     printf("%d", ans);  
89     for(int i = 0; i < X.size(); i++) printf(" r%d", X[i]+1);  
90     for(int i = 0; i < Y.size(); i++) printf(" c%d", Y[i]+1);  
91     printf("
");  
92   }  
93   return 0;  
94 }  
原文地址:https://www.cnblogs.com/zyb993963526/p/6900833.html