标签:
题意:http://vjudge.net/problem/UVA-12549
分析:
一个重要位置有(x,y)两个坐标,而要守住这个重要位置就相当于连一条x到y的弧。选了一个重要位置(x,y)放置机器人相当于选了所有x相同的弧或者y相同的弧。当所有的x或者y被选完的时候就完成了看守。具体来说二分图两列分别表示用编号代表行和列,从源点s向行连一条容量为1的弧,从列向汇点t连一条容量为1的弧,再对于每个重要位置(x,y),连一条从x指向y容量为1的弧,跑一次s-t的最大流,最大流出现是当源点s连出去的弧或者连向汇点的弧全部满载(表示图中行或者列全部被选完)的时候,即完成了二分图最大匹配==最小点集覆盖。有障碍物的情况下需要拆行拆列。
1 #include <cstdio> 2 #include <set> 3 #include <queue> 4 #include <cstring> 5 #include <vector> 6 #include <algorithm> 7 using namespace std; 8 9 const int maxn = 10000 + 5; 10 const int INF = 0x3f3f3f3f; 11 12 struct Edge { 13 int from, to, cap, flow; 14 Edge(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f) {} 15 }; 16 17 struct EdmondsKarp { 18 int n, m; 19 vector<Edge> edges; 20 vector<int> G[maxn]; 21 int a[maxn]; 22 int p[maxn]; 23 24 void init(int n) { 25 for (int i = 0; i < n; i++) G[i].clear(); 26 edges.clear(); 27 } 28 29 void AddEdge(int from, int to, int cap) { 30 edges.push_back(Edge(from, to, cap, 0)); 31 edges.push_back(Edge(to, from, 0, 0)); 32 m = edges.size(); 33 G[from].push_back(m - 2); 34 G[to].push_back(m - 1); 35 } 36 37 int Maxflow(int s, int t) { 38 int flow = 0; 39 for (;;) { 40 memset(a, 0, sizeof(a)); 41 queue<int> Q; 42 Q.push(s); 43 a[s] = INF; 44 while (!Q.empty()) { 45 int x = Q.front(); Q.pop(); 46 for (int i = 0; i < G[x].size(); i++) { 47 Edge& e = edges[G[x][i]]; 48 if (!a[e.to] && e.cap > e.flow) { 49 p[e.to] = G[x][i]; 50 a[e.to] = min(a[x], e.cap - e.flow); 51 Q.push(e.to); 52 } 53 } 54 if (a[t]) break; 55 } 56 if (!a[t]) break; 57 for (int u = t; u != s; u = edges[p[u]].from) { 58 edges[p[u]].flow += a[t]; 59 edges[p[u] ^ 1].flow -= a[t]; 60 } 61 flow += a[t]; 62 } 63 return flow; 64 } 65 }; 66 67 EdmondsKarp g; 68 69 int mp[105][105]; 70 int row[105][105]; 71 int col[105][105]; 72 73 int main() { 74 int T; 75 scanf("%d", &T); 76 while (T--) { 77 int r, c, p; 78 scanf("%d%d%d", &r, &c, &p); 79 memset(mp, 0, sizeof(mp)); 80 int x, y; 81 while (p--) { 82 scanf("%d%d", &x, &y); 83 mp[x][y] = 1; 84 } 85 scanf("%d", &p); 86 while (p--) { 87 scanf("%d%d", &x, &y); 88 mp[x][y] = 2; 89 } 90 memset(row, 0, sizeof(row)); 91 memset(col, 0, sizeof(col)); 92 int cnt = 0; 93 for (int i = 1; i <= r; i++) { 94 bool ob = true; 95 for (int j = 1; j <= c; j++) { 96 if (mp[i][j] == 1) { 97 if (ob) cnt++; 98 row[i][j] = cnt; 99 ob = false; 100 } else if (mp[i][j] == 2) ob = true; 101 } 102 } 103 for (int j = 1; j <= c; j++) { 104 bool ob = true; 105 for (int i = 1; i <= r; i++) { 106 if (mp[i][j] == 1) { 107 if (ob) cnt++; 108 col[i][j] = cnt; 109 ob = false; 110 } else if (mp[i][j] == 2) ob = true; 111 } 112 } 113 g.init(cnt + 2); 114 set<int> st; 115 for (int i = 1; i <= r; i++) 116 for (int j = 1; j <= c; j++) 117 if (row[i][j]) st.insert(row[i][j]); 118 for (set<int>::iterator it = st.begin(); it != st.end(); it++) 119 g.AddEdge(0, *it, 1); 120 st.clear(); 121 for (int j = 1; j <= c; j++) 122 for (int i = 1; i <= r; i++) 123 if (col[i][j]) st.insert(col[i][j]); 124 for (set<int>::iterator it = st.begin(); it != st.end(); it++) 125 g.AddEdge(*it, cnt + 1, 1); 126 for (int i = 1; i <= r; i++) 127 for (int j = 1; j <= c; j++) 128 if (mp[i][j] == 1) g.AddEdge(row[i][j], col[i][j], 1); 129 printf("%d\n", g.Maxflow(0, cnt + 1)); 130 } 131 return 0; 132 }
UVa12549 Sentry Robots (二分图最大匹配,最小点集覆盖)
标签:
原文地址:http://www.cnblogs.com/XieWeida/p/5907790.html