题意:一个矩形中,有N个城市’*’,现在这n个城市都要覆盖无线,若放置一个基站,那么它至多可以覆盖相邻的两个城市。问至少放置多少个基站才能使得所有的城市都覆盖无线?
思路:一个基站相当于一条边,连接相邻的节点。显然就是选取最少的边数使得其能够覆盖所有的顶点。又因为在二分图中最小边覆盖=n-最大匹配。所以题目就转化成了求最大匹配数。建图还是要好好想想,图中的相邻点点对处于不同的部集中。(她的构图貌似容易一些http://blog.youkuaiyun.com/lyy289065406/article/details/6647040)
#include <stdio.h>
#include <string.h>
#define N 420
#define M 2200
char s[N][N];
int T,n,m;
int g[M][M];
int link[M],used[M];
int id(int x,int y){
return (x*m+y);
}
int dfs(int i){
int j;
for(j = 0;j<m;j++)
if(g[i][j] && !used[j]){
used[j] = 1;
if(link[j] == -1 || dfs(link[j])){
link[j] = i;
return 1;
}
}
return 0;
}
int hungray(){
int i,res= 0;
for(i = 0;i<n;i++){
memset(used,0,sizeof(used));
if(dfs(i))
res++;
}
return res;
}
int main(){
freopen("a.txt","r",stdin);
scanf("%d",&T);
while(T--){
int i,j,sum=0;//sum用来计算二分图节点的总数
memset(link,-1,sizeof(link));
memset(g,0,sizeof(g));
memset(s,' ',sizeof(s));
scanf("%d %d\n",&n,&m);
for(i = 0;i<n;i++)
scanf("%s",s[i]);
if((m&1) == 0)//如果列宽是偶数则加一,方便构图,使得二部图一部的坐标序号始终以奇偶区分
m++;
if(s[0][0] == '*')
sum++;
for(i = 1;i<m;i++)//对第一行的边构图
if(s[0][i]=='*'){
sum++;
if(s[0][i-1]=='*')
if(i&1)
g[i/2][i/2] = 1;
else
g[i/2][(i-1)/2] = 1;
}
for(i = 1;i<n;i++)//对第一列的边构图
if(s[i][0]=='*'){
sum++;
if(s[i-1][0]=='*')
if(i&1)
g[(i-1)*m/2][i*m/2] = 1;
else
g[i*m/2][(i-1)*m/2] = 1;
}
for(i = 1;i<n;i++)//对其他边构图,只需遍历节点看其与左或上邻域是否存在边
for(j = 1;j<m;j++)
if(s[i][j]=='*'){
sum++;
if(s[i-1][j]=='*'){
if(id(i,j)&1)
g[id(i-1,j)>>1][id(i,j)>>1] = 1;
else
g[id(i,j)>>1][id(i-1,j)>>1] = 1;
}
if(s[i][j-1]=='*'){
if(id(i,j)&1)
g[id(i,j-1)>>1][id(i,j)>>1] = 1;
else
g[id(i,j)>>1][id(i,j-1)>>1] = 1;
}
}
n = m = n*m/2+1;//n、m存为二部图的一部节点大小
printf("%d\n",sum-hungray());
}
return 0;
}