POJ-3020 Antenna Placement---二分图匹配&最小路径覆盖&建图

题目链接:

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 }

 

posted @ 2018-04-14 23:04  _努力努力再努力x  阅读(175)  评论(0编辑  收藏  举报