| 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