POJ 3020(最小路径覆盖+拆点)

题意:一个矩形中,有N个城市’*’,现在这n个城市都要覆盖无线,若放置一个基站,那么它至多可以覆盖相邻的两个城市。
问至少放置多少个基站才能使得所有的城市都覆盖无线?

 

思路:每个城市才是要构造的二分图的顶点,先把每个*用数字1-n标记起来,然后构造无向二分图,无向二分图的构造需要拆点,即1<—>2之间的双向边要拆成两条有向边,1—>2',2—>1'。且点集(1,2)(2',1')分别属于二分图的两个顶点集V1,V2。再跑一遍匈牙利,结果就是 “顶点数—最大匹配数/2”。

 

二分图的一点小知识:

最大匹配: 图中包含边数最多的匹配称为图的最大匹配。 
完美匹配: 如果所有点都在匹配边上,称这个最大匹配是完美匹配。
最小覆盖: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆盖数)=最大匹配数
最小路径覆盖:
用尽量少的不相交简单路径覆盖有向无环图G的所有结点。解决此类问题可以建立一个二分图模型。把所有顶点i拆成两个:X结点集中的i和Y结点集中的i',如果有边i->j,则在二分图中引入边i->j',设二分图最大匹配为m,则结果就是n-m。
最大独立集问题:
在N个点的图G中选出m个点,使这m个点两两之间没有边.求m最大值.
如果图G满足二分图条件,则可以用二分图匹配来做.最大独立集点数 = N - 最大匹配数。

  1 #include <iostream>
  2 #include <queue>
  3 #include <stack>
  4 #include <cstdio>
  5 #include <vector>
  6 #include <map>
  7 #include <set>
  8 #include <bitset>
  9 #include <algorithm>
 10 #include <cmath>
 11 #include <cstring>
 12 #include <cstdlib>
 13 #include <string>
 14 #include <sstream>
 15 #include <time.h>
 16 #define x first
 17 #define y second
 18 #define pb push_back
 19 #define mp make_pair
 20 #define lson l,m,rt*2
 21 #define rson m+1,r,rt*2+1
 22 #define mt(A,B) memset(A,B,sizeof(A))
 23 using namespace std;
 24 typedef long long LL;
 25 //const double PI = acos(-1);
 26 const int N=4e2+10;
 27 const LL mod=1e9+7;
 28 const int inf = 0x3f3f3f3f;
 29 const LL INF=0x3f3f3f3f3f3f3f3fLL;
 30 int un,vn,n;
 31 int g[N][N];
 32 int linker[N];
 33 bool used[N];
 34 char s[N][N];
 35 int vis[N][N];
 36 bool dfs(int u)
 37 {
 38     for(int v=1;v<=vn;v++)
 39     {
 40         if(g[u][v]&&!used[v])
 41         {
 42             used[v]=true;
 43             if(linker[v]==-1||dfs(linker[v]))
 44             {
 45                 linker[v]=u;
 46                 return true;
 47             }
 48         }
 49     }
 50     return false;
 51 }
 52 int hungary()
 53 {
 54     int res=0;
 55     mt(linker,-1);
 56     for(int i=1;i<=un;i++)
 57     {
 58         mt(used,false);
 59         if(dfs(i))res++;
 60     }
 61     return res;
 62 }
 63 int main()
 64 {
 65 #ifdef Local
 66     freopen("data.txt","r",stdin);
 67 #endif
 68     //ios::sync_with_stdio(false);
 69    // cin.tie(0);
 70     int T,k;
 71     cin>>T;
 72     while(T--)
 73     {
 74         k=1;
 75         mt(g,0);
 76         mt(vis,0);
 77         cin>>un>>vn;
 78         //cout<<un<<" "<<vn<<endl;
 79         for(int i=0;i<un;i++)
 80         {
 81             scanf("%s",s[i]);
 82         }
 83         for(int i=0;i<un;i++)
 84         {
 85             for(int j=0;j<vn;j++)
 86             {
 87                 if(s[i][j]=='*')
 88                 {
 89                     vis[i][j]=k;
 90                     k++;
 91                 }
 92             }
 93         }
 94         for(int i=0;i<un;i++)
 95         {
 96             for(int j=0;j<vn;j++)
 97             {
 98                 if(vis[i][j])
 99                 {
100                     if(i+1<un&&vis[i+1][j])
101                     {
102                         g[vis[i][j]][vis[i+1][j]]=1;
103                         g[vis[i+1][j]][vis[i][j]]=1;
104                     }
105                     if(i-1>=0&&vis[i-1][j])
106                     {
107                         g[vis[i][j]][vis[i-1][j]]=1;
108                         g[vis[i-1][j]][vis[i][j]]=1;
109                     }
110                     if(j+1<vn&&vis[i][j+1])
111                     {
112                         g[vis[i][j]][vis[i][j+1]]=1;
113                         g[vis[i][j+1]][vis[i][j]]=1;
114                     }
115                     if(j-1>=0&&vis[i][j-1])
116                     {
117                         g[vis[i][j]][vis[i][j-1]]=1;
118                         g[vis[i][j-1]][vis[i][j]]=1;
119                     }
120                 }
121             }
122         }
123         un=vn=k;
124         cout<<k-hungary()/2-1<<endl;
125     }
126 #ifdef Local
127     cerr << "time: " << (LL) clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
128 #endif
129 }
View Code

 

posted @ 2017-03-28 21:39  Kcl886  阅读(216)  评论(0编辑  收藏  举报