Uva 11419 我是SAM
Posted 树的种子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Uva 11419 我是SAM相关的知识,希望对你有一定的参考价值。
题目链接:https://vjudge.net/problem/UVA-11419
题意:一个网格里面有一些目标,可以从某一行,某一列发射一发子弹,可以打穿;
求最少的子弹,和在哪里打?
分析:
听说可以用吗MCMF做,没多想;
一个目标,拆成两个点,X,Y,X与Y之间连一条边,现在,在这些点里面选出一些点,使得每一条边都有一个端点被覆盖,这就是最小点覆盖=最大匹配(证明在之前写过,博客里可以找到,证明很有意思);
然后还要找出哪些被覆盖了;
1 // UVa11419 SAM I AM 2 // Rujia Liu 3 #include <cstdio> 4 #include <cstring> 5 #include <vector> 6 #include <algorithm> 7 using namespace std; 8 9 const int maxn = 1000 + 5; // 单侧顶点的最大数目 10 11 // 二分图最大基数匹配 12 struct BPM 13 { 14 int n, m; // 左右顶点个数 15 vector<int> G[maxn]; // 邻接表 16 int left[maxn]; // left[i]为右边第i个点的匹配点编号,-1表示不存在 17 bool T[maxn]; // T[i]为右边第i个点是否已标记 18 19 int right[maxn]; // 求最小覆盖用 20 bool S[maxn]; // 求最小覆盖用 21 22 void init(int n, int m) 23 { 24 this->n = n; 25 this->m = m; 26 for(int i = 0; i < n; i++) G[i].clear(); 27 } 28 29 void AddEdge(int u, int v) 30 { 31 G[u].push_back(v); 32 } 33 34 bool match(int u) 35 { 36 S[u] = true; 37 for(int i = 0; i < G[u].size(); i++) 38 { 39 int v = G[u][i]; 40 if (!T[v]) 41 { 42 T[v] = true; 43 if (left[v] == -1 || match(left[v])) 44 { 45 left[v] = u; 46 right[u] = v; 47 return true; 48 } 49 } 50 } 51 return false; 52 } 53 54 // 求最大匹配 55 int solve() 56 { 57 memset(left, -1, sizeof(left)); 58 memset(right, -1, sizeof(right)); 59 int ans = 0; 60 for(int u = 0; u < n; u++) // 从左边结点u开始增广 61 { 62 memset(S, 0, sizeof(S)); 63 memset(T, 0, sizeof(T)); 64 if(match(u)) ans++; 65 } 66 return ans; 67 } 68 69 // 求最小覆盖。X和Y为最小覆盖中的点集 70 int mincover(vector<int>& X, vector<int>& Y) 71 { 72 int ans = solve(); 73 memset(S, 0, sizeof(S)); 74 memset(T, 0, sizeof(T)); 75 for(int u = 0; u < n; u++) 76 if(right[u] == -1) match(u); // 从所有X未盖点出发增广 77 for(int u = 0; u < n; u++) 78 if(!S[u]) X.push_back(u); // X中的未标记点 79 for(int v = 0; v < m; v++) 80 if(T[v]) Y.push_back(v); // Y中的已标记点 81 return ans; 82 } 83 }; 84 85 BPM solver; 86 87 int R, C, N; 88 89 int main() 90 { 91 int kase = 0; 92 while(scanf("%d%d%d", &R, &C, &N) == 3 && R && C && N) 93 { 94 solver.init(R, C); 95 for(int i = 0; i < N; i++) 96 { 97 int r, c; 98 scanf("%d%d", &r, &c); 99 r--; 100 c--; 101 solver.AddEdge(r, c); 102 } 103 vector<int> X, Y; 104 int ans = solver.mincover(X, Y); 105 printf("%d", ans); 106 for(int i = 0; i < X.size(); i++) printf(" r%d", X[i]+1); 107 for(int i = 0; i < Y.size(); i++) printf(" c%d", Y[i]+1); 108 printf("\n"); 109 } 110 return 0; 111 }
以上是关于Uva 11419 我是SAM的主要内容,如果未能解决你的问题,请参考以下文章