题目链接:
https://vjudge.net/problem/POJ-3020
题目大意:
一个n*m的方阵 一个雷达可覆盖两个*,一个*可与四周的一个*被覆盖,一个*可被多个雷达覆盖问至少需要多少雷达能把所有的*覆盖
解题思路:
把每个*城市编号,然后每相邻两个城市之间连线。这里求最少多少个雷达可以覆盖完*,就是二分图匹配中的最小路径覆盖数,但是这里的图的边是双向的。举个例子
o*o
**o
ooo
这里可以编号成
010
230
000
那么有边<1,3><3,1><2,3><3,2>
按照二分图匹配建图的方法,每个点拆分成两个点A1,A2,如果有边<A, B>在二分图中建立边<A1, B2>。
这里的特殊性在于1和3有边,3和1也有边,所以最后求出来的最大匹配需要除以2才是题目所需要的最大匹配
最小路径覆盖数 = 顶点数 - 最大匹配
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 using namespace std; 8 typedef pair<int, int> Pair ; 9 typedef long long ll; 10 const int INF = 0x3f3f3f3f; 11 const int maxn = 500 + 10; 12 int T, n, m, cases; 13 vector<int>G[maxn]; 14 int cx[maxn], cy[maxn]; 15 bool vis[maxn]; 16 char Map[50][50]; 17 int cnt[50][50], tot; 18 int dir[4][2] = {1,0,0,1,-1,0,0,-1}; 19 bool dfs(int u) 20 { 21 for(int i = 0; i < G[u].size(); i++) 22 { 23 int v = G[u][i]; 24 if(!vis[v]) 25 { 26 vis[v] =1;//加入增广路 27 if(cy[v] == -1 || dfs(cy[v])) 28 { 29 cx[u] = v; 30 cy[v] = u; 31 return 1; 32 } 33 } 34 } 35 return 0; 36 } 37 38 int maxmatch() 39 { 40 int ans = 0; 41 memset(cx, -1, sizeof(cx)); 42 memset(cy, -1, sizeof(cy)); 43 for(int i = 1; i <= tot; i++) 44 { 45 if(cx[i] == -1) 46 { 47 memset(vis, 0, sizeof(vis)); 48 ans += dfs(i); 49 } 50 } 51 return ans; 52 } 53 54 int main() 55 { 56 cin >> T; 57 while(T--) 58 { 59 scanf("%d%d", &n, &m); 60 tot = 0; 61 for(int i = 0; i < maxn; i++)G[i].clear(); 62 for(int i = 0; i < n; i++)//将Map转化成城市的编号 63 { 64 cin >> Map[i]; 65 for(int j = 0; j < m ;j++) 66 if(Map[i][j] == 'o')cnt[i][j] = 0; 67 else cnt[i][j] = ++tot; 68 }/* 69 for(int i = 0; i < n; i++) 70 { 71 for(int j = 0; j < m; j++)cout<<cnt[i][j]<<" "; 72 cout<<endl; 73 }*/ 74 for(int i = 0; i < n; i++) 75 //二分图建图,每个点拆成两个点,建成有向图,并且每两点之间有两条相反边,所以求出来的最大匹配是真正匹配的两倍 76 { 77 for(int j = 0; j < m; j++) 78 { 79 if(!cnt[i][j])continue; 80 for(int k = 0; k < 4; k++) 81 { 82 int xx = i + dir[k][0]; 83 int yy = j + dir[k][1]; 84 if(!cnt[xx][yy])continue; 85 if(xx < 0 || xx >= n || yy < 0 || yy >= m)continue; 86 int u = cnt[i][j], v = cnt[xx][yy]; 87 //cout<<u<<" "<<v<<endl; 88 G[u].push_back(v); 89 } 90 } 91 } 92 //最小路径覆盖数 = 顶点数 - 最大匹配数 93 int ans = tot - maxmatch() / 2; 94 cout<<ans<<endl; 95 } 96 return 0; 97 }