poj 3020 二分图最小边覆盖(建立天线覆盖节点)

题意:一个矩形中,有N个城市’*’,现在这n个城市都要覆盖无线,若放置一个基站,那么它至多可以覆盖相邻的两个城市。问至少放置多少个基站才能使得所有的城市都覆盖无线?

思路:一个基站相当于一条边,连接相邻的节点。显然就是选取最少的边数使得其能够覆盖所有的顶点。又因为在二分图中最小边覆盖=n-最大匹配。所以题目就转化成了求最大匹配数。建图还是要好好想想,图中的相邻点点对处于不同的部集中。(她的构图貌似容易一些http://blog.csdn.net/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;
}


你可能感兴趣的:(poj 3020 二分图最小边覆盖(建立天线覆盖节点))