Description
Input
Output
Sample Input
2 7 9 ooo**oooo **oo*ooo* o*oo**o** ooooooooo *******oo o*o*oo*oo *******oo 10 1 * * * o * * * * * *
Sample Output
17 5
题意:给出‘*‘代表城市,求最少的基站能够覆盖所有的城市,一个基站能覆盖两个相邻的城市。
思路:基站其实就是一条边,就是求最小边覆盖。
而边覆盖数+边独立数=顶点数。
即最小边覆盖数=顶点数-边独立数,边独立数又叫做最大匹配数。所以求出最大匹配数就可以了。而建图比较难,这题想了好久,其实因为一个基站能覆盖相邻的城市,所以把每个城市及其上下左右相邻的加入二分图就可以了,可以用邻接表实现,用vector代替平常的邻接表。而这些城市最先得先加序号,因为匈牙利算法中要标号,如果不加序号的话,那么就不能标号了,也会标号混乱,不易实现。
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <list> #include <queue> #include <string> #include <cstring> #include <map> #include <set> #define PI acos(-1.0) #define mem(a,b) memset(a,b,sizeof(a)) #define sca(a) scanf("%d",&a) #define pri(a) printf("%d\n",a) #define MM 10002 #define MN 505 #define INF 168430090 using namespace std; typedef long long ll; int n,h,w,t,m,pre[MN],vis[MN]; vector<int>q[MN]; int dfs(int x) { for(int i=0; i<q[x].size();i++) { int y=q[x][i]; if(!vis[y]) { vis[y]=1; if(pre[y]==0||dfs(pre[y])) //dfs前向结点,如果为真说明找到增广路 { pre[y]=x; //把匹配的变成未匹配,未匹配的变成匹配,故匹配数+1,因为未匹配数比匹配数大1 return 1; } } } return 0; } void search() { for(int x=1; x<n; x++) //从左顶点集开始判断 { mem(vis,0); if(dfs(x)) m++; } } int main() { cin>>t; while(t--) { char Map1[40][11]; int i,j,k,Map[40][11],dis[4][2]= {0,1,0,-1,-1,0,1,0}; n=1; m=0; mem(Map,0); mem(pre,0); cin>>h>>w; for(i=0; i<h; i++) cin>>Map1[i]; for(i=0; i<h; i++) for(j=0; j<w; j++) if(Map1[i][j]==‘*‘) Map[i][j]=n++; //顺序加序号 for(i=0;i<=503;i++) q[i].clear(); for(i=0; i<h; i++) for(j=0; j<w; j++) { int a,b,x=Map[i][j]; if(x) for(k=0; k<4; k++) { a=i+dis[k][0]; //把上下左右的点符合的加入二分图 b=j+dis[k][1]; if(a>=0&&a<h&&b>=0&&b<w&&Map[a][b]) q[x].push_back(Map[a][b]); } } search(); cout<<n-1-m/2<<endl; //因为是无向图,而匈牙利算法中是有向的,所以每条边匹配了两次。比如:4和5,第一次匹配了4->5,第二次又匹配了5->4,故除2 } return 0; }
CUGB图论专场2:A - Antenna Placement 二分图最小边覆盖
原文:http://blog.csdn.net/u011466175/article/details/19247843