POJ - 3020 Antenna Placement 二分图最大匹配
http://poj.org/problem?id=3020
首先注意到,答案的最大值是'*'的个数,也就是相当于我每用一次那个技能,我只套一个'*',是等价的。
所以,每结合一对**,则可以减少一次使用,所以就是找**的最大匹配数目。
对于每一个*,和它的上下左右连接一条边(如果是*才连)
那么,这个图是一个二分图,怎么找到左边集合S,右边集合T呢?
我的做法是染色一次,就可以。
这题应该不能贪心吧。
3 5
*****
o***o
o*o*o
其实也可以不分开S、T
跑一发最大匹配,然后匹配数 / 2即可。意思就是match[1] = 2,也可以match[2] = 1,但是两者是只算一个匹配。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> const int maxn = 40 + 20; char str[maxn][maxn]; int a[maxn][maxn]; struct Node { int u, v, tonext; }e[maxn * maxn * 3]; int first[maxn * maxn * 3], num; void addEdge(int u, int v) { ++num; e[num].u = u, e[num].v = v; e[num].tonext = first[u]; first[u] = num; } int match[maxn * maxn * 3], book[maxn * maxn * 3], DFN; bool dfs(int u) { for (int i = first[u]; i; i = e[i].tonext) { int v = e[i].v; if (book[v] == DFN) continue; book[v] = DFN; if (match[v] == 0 || dfs(match[v])) { match[v] = u; return true; } } return false; } vector<int>vc; int hungary() { memset(match, 0, sizeof match); int ans = 0; for (int i = 0; i < vc.size(); ++i) { ++DFN; if (dfs(vc[i])) ans++; } return ans; } int col[maxn * maxn * 3]; void ran(int cur, int which) { col[cur] = which; book[cur] = DFN; for (int i = first[cur]; i; i = e[i].tonext) { int v = e[i].v; if (book[v] == DFN) continue; ran(v, !which); } } void work() { memset(first, 0, sizeof first); num = 0; int to = 0; int n, m; cin >> n >> m; for (int i = 1; i <= n; ++i) { scanf("%s", str[i] + 1); } memset(a, 0, sizeof a); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (str[i][j] == '*') { a[i][j] = ++to; } } } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (a[i][j + 1]) addEdge(a[i][j], a[i][j + 1]); if (a[i + 1][j]) addEdge(a[i][j], a[i + 1][j]); if (a[i][j - 1]) addEdge(a[i][j], a[i][j - 1]); if (a[i - 1][j]) addEdge(a[i][j], a[i - 1][j]); } } memset(col, -1, sizeof col); ++DFN; for (int i = 1; i <= to; ++i) { if (book[i] != DFN) ran(i, 0); } vc.clear(); for (int i = 1; i <= to; ++i) { if (col[i] == 1) vc.push_back(i); } cout << to - hungary() << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif int t; cin >> t; while (t--) work(); return 0; }
既然选择了远方,就要风雨兼程~
posted on 2017-03-27 09:48 stupid_one 阅读(147) 评论(0) 编辑 收藏 举报