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 - 最大匹配数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }