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

来源:互联网 发布:如何查看手机端口号 编辑:程序博客网 时间:2024/05/19 22:44

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

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


#include <stdio.h>#include <string.h>#define N 420#define M 2200char 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;elseg[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;elseg[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;elseg[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;elseg[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;}


0 0
原创粉丝点击