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