Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 6930 | Accepted: 3439 |
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
题意:在一个h*w的矩阵中,*代表城市,o表示空地,城市需要覆盖无线网,若放置一个基站,可以覆盖相邻的两个城市,问最少要放置多少个基站才能将所有的城市覆盖。
思路:这道题目难点不是二分图的问题,却是建图的问题。到底是有向图还是无向图,因为这两个的建图方式是不同的,这道题是个有向图,这里不是把城市的x,y坐标当做点集,而是将一个一个的城市当做点集,构造方法如下(转)
例如输入:
*oo
***
O*o
时,可以抽象为一个数字地图:
100
234
050
数字就是根据输入的城市次序作为该城市的编号,0代表该位置没有城市。
然后根据题目的“范围”规则,从第一个城市开始,以自身作为中心城市,向四个方向的城市进行连线(覆盖)
因此就能够得到边集:
e12 e21 e32 e43 e53
e23 e34
e35
可以看到,这些边都是有向边,但是每一条边都有与其对应的一条相反边。
即任意两个城市(顶点)之间的边是成对出现的
那么我们就可以确定下来,应该 构造无向二分图(其实无向=双向)
把原有向图G的每一个顶点都”拆分(我认为复制更准确)”为2个点,分别属于所要构造的二分图的两个顶点集
那么同理就可以得到刚才的例子的 无向二分图为:
再继而通过无向二分图,以V1的元素作为row,V2的元素作为col,构造 可达矩阵 存储到计算机
1’ 2’ 3’ 4’ 5’
1 F T F F F
2 T F T F F
3 F T F T T
4 F F T F F
5 F F T F F
接下来就是要求这个 无向二分图的最小路径覆盖 了
利用公式:
无向二分图的最小路径覆盖 = 顶点数 – 最大二分匹配数/2。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; struct node { int v,w; int next; } edge[10010]; int cnt,k; int head[500]; int vis[500]; int link[500]; int map[100][100]; int jx[]= {-1,0,1,0}; int jy[]= {0,1,0,-1}; void add(int u,int v,int w) { edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; } int dfs(int u) { int i; for(i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; if(!vis[v]) { vis[v]=1; if(link[v]==-1||dfs(link[v])) { link[v]=u; return 1; } } } return 0; } int main() { int T,i,j,l; int h,w; char str; scanf("%d",&T); while(T--) { memset(head,-1,sizeof(head)); memset(link,-1,sizeof(link)); memset(map,0,sizeof(map)); k=0; cnt=0; scanf("%d %d",&h,&w); for(i=1; i<=h; i++) { for(j=1; j<=w; j++) { cin>>str; if(str=='*') map[i][j]=++k; } } for(i=1; i<=h; i++) { for(j=1; j<=w; j++) { if(map[i][j]) { for(l=0; l<4; l++) { if(map[i+jx[l]][j+jy[l]]) { add(map[i][j],map[i+jx[l]][j+jy[l]],1); add(map[i+jx[l]][j+jy[l]],map[i][j],1); } } } } } int sum=0; for(i=1;i<=k;i++) { memset(vis,0,sizeof(vis)); sum+=dfs(i); } printf("%d\n",k-sum/2);//无向二分图:最小路径覆盖数 = "拆点"前原图的顶点数 - 最大匹配数/2 } }
POJ 3020-Antenna Placement(二分图匹配_最小路径覆盖+前向星构图)
原文地址:http://blog.csdn.net/u013486414/article/details/42672115