题目大意:
一个矩形中,有N个城市’*’,现在这n个城市都要覆盖无线,若放置一个基站,那么它至多可以覆盖相邻的两个城市。
问至少放置多少个基站才能使得所有的城市都覆盖无线?
解题思路:
先对图中的所有城市进行编号:
列如:
*oo
***
o*o
可以将此图转化为:
100
234
506
每个城市和其相邻的城市之间可以共用一个信号塔,那么可以将两个相邻城市用一条线来表示,线的两个端点是两个相邻的城市。然后将图用邻接矩阵表示。那么上面的图就可以转化为:
1 2 3 4 5 6
1 0 1 0 0 0 0
2 1 0 1 0 1 0
3 0 1 0 1 0 0
4 0 0 1 0 0 1
5 0 1 0 0 0 0
6 0 0 0 1 0 0
然后就可以用匈牙利算法计算最大二分匹配数了。
需要注意的是此图是无向图,所以所有的匹配数都计算了两次,在最后计算的时候要除以二。
根据公式:无向二分图的最小路径覆盖 = 顶点数 – 最大二分匹配数/2
得出结果。
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<queue>
#include<stack>
#include<queue>
#include<algorithm>
using namespace std;
char a[500][500];
int map[500][500],line[500][500],vis[500],mark[500];
int dir4[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int m,n,num;
bool judge(int x,int y)//判断是否越界
{
if(x>=0&&x<m&&y>=0&&y<n)
return true;
return false;
}
bool find(int x)//匈牙利算法计算最大二分匹配数
{
for(int i=1;i<num;i++)
if(line[x][i]==1&&!vis[i])
{
vis[i]=1;
if(mark[i]==0||find(mark[i]))
{
mark[i]=x;
return true;
}
}
return false;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
memset(a,0,sizeof(a));
memset(map,0,sizeof(map));
memset(line,0,sizeof(line));
memset(mark,0,sizeof(mark));
scanf("%d%d",&m,&n);
for(int i=0;i<m;i++)
scanf("%s",a[i]);
num=1;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
if(a[i][j]=='*')
{
map[i][j]=num;
num++;
}
for(int i=0;i<m;i++)//将图转化为邻接矩阵
for(int j=0;j<n;j++)
if(map[i][j])
for(int k=0;k<4;k++)
{
if(judge(i+dir4[k][0],j+dir4[k][1])&&map[i+dir4[k][0]][j+dir4[k][1]])
line[map[i][j]][map[i+dir4[k][0]][j+dir4[k][1]]]=1;
}
int sum=0;
for(int i=1;i<num;i++)//计算最大二分匹配数
{
memset(vis,0,sizeof(vis));
if(find(i))
sum++;
}
printf("%d\n",num-1-sum/2);
}
return 0;
}