poj 3020 Antenna Placement (最小路径覆盖, 匈牙利算法, 拆点形成二分图)
2017-03-21 20:14
253 查看
题意: 给出网格, 每个点有两种可能: 空地或者城市. 现在要建立无线网络区, 每个无线网络区只能放在城市中, 并且只能朝东南西北某一个方向覆盖另外一个城市(必须相邻), 求最少要建立几个无线网络区才能覆盖所有的城市.
分析: 如果把每个无线网络所在城市与其覆盖的另一个城市之间视作一条路径的话, 那么所有的城市都只能属于其中一条路径, 所以题目可以理解为, 存在多少条路径可以覆盖掉所有的城市, 即最小路径覆盖数. 又 最小路径覆盖数 = 总点数|P| - 最大匹配数. 所以可以通过将所有城市之间的相邻关系建立成一张图, 再求最大匹配数(可采用匈牙利算法).
建图: 题目给的是以(*,o)组成的网格.可以将*所在位置以数字进行编号, 如
oo**oo
*o*oo*
***o*o
可编号为:
001200
304005
678090
由于每个点都可能作为无线网络区去对相邻点覆盖即存在1->2和2->1的情况, 说明该图可为无向图.
要求最大匹配数就得将图拆成二分图. 我们可以采用拆点的方法, 即一个点拆成两个点, 分别置于V集合和V'集合,这样就可以形成二分图, 点集两边点数相等.
(注意:此时求出的最大匹配数为原图的2倍, 原因是: 假如V集中点1与V'集中点2'相匹配, 则由于拆点的关系, 必定存在V集中点2与V'集中点1'相匹配.故最后计算的时候应该除以2).
最小路径覆盖数 = 总点数|P|- 最大匹配数 . 证明参考百度百科:
最小路径覆盖公式证明
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<cstdio>
using namespace std;
int n, m, len, ans;
int Map[550
4000
][550];
int edge[550][550];
int d[4][2]={{-1, 0}, {0,-1}, {1, 0}, {0, 1}};
int flag[550], link[550];
bool dfs(int x){
int y;
for(y=1; y<=len; y++){
if(edge[x][y] && !flag[y]){
flag[y]=1;
if(link[y]==0 || dfs(link[y])){
link[y] = x;
return true;
}
}
}
return false;
}
int main(){
int T, i, j, k;
scanf("%d", &T);
while(T--){
//注意初始化
memset(link, 0, sizeof(link));
memset(Map, 0, sizeof(Map));
memset(edge, 0, sizeof(edge));
scanf("%d %d%*c", &n, &m);
char c;
len=0;
for(i=1; i<=n; i++){
for(j=1; j<=m; j++){
scanf("%c", &c);
if(c=='*'){
Map[i][j] = ++len;//给每个城市编号, Map存每个城市的编号
}
}
getchar();
}
//建图 -> 拆点
int x, y;
for(i=1; i<=n; i++){
for(j=1; j<=m; j++){
if(Map[i][j]){
int id = Map[i][j];
for(k=0; k<4; k++){//东南西北连边中~~~
x = i+d[k][0];
y = j+d[k][1];
int idd = Map[x][y];
if(Map[x][y]) edge[id][idd]=1;
}
}
}
}
ans=0;
for(i=1;i<=len; i++){
memset(flag, 0, sizeof(flag));
if(dfs(i)) ans++;
}
//len是总点数, ans是上图求出的最大匹配数, 应当除以2才是原集合的最大匹配数
printf("%d\n", len-ans/2);
}
return 0;
}
分析: 如果把每个无线网络所在城市与其覆盖的另一个城市之间视作一条路径的话, 那么所有的城市都只能属于其中一条路径, 所以题目可以理解为, 存在多少条路径可以覆盖掉所有的城市, 即最小路径覆盖数. 又 最小路径覆盖数 = 总点数|P| - 最大匹配数. 所以可以通过将所有城市之间的相邻关系建立成一张图, 再求最大匹配数(可采用匈牙利算法).
建图: 题目给的是以(*,o)组成的网格.可以将*所在位置以数字进行编号, 如
oo**oo
*o*oo*
***o*o
可编号为:
001200
304005
678090
由于每个点都可能作为无线网络区去对相邻点覆盖即存在1->2和2->1的情况, 说明该图可为无向图.
要求最大匹配数就得将图拆成二分图. 我们可以采用拆点的方法, 即一个点拆成两个点, 分别置于V集合和V'集合,这样就可以形成二分图, 点集两边点数相等.
(注意:此时求出的最大匹配数为原图的2倍, 原因是: 假如V集中点1与V'集中点2'相匹配, 则由于拆点的关系, 必定存在V集中点2与V'集中点1'相匹配.故最后计算的时候应该除以2).
最小路径覆盖数 = 总点数|P|- 最大匹配数 . 证明参考百度百科:
最小路径覆盖公式证明
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<cstdio>
using namespace std;
int n, m, len, ans;
int Map[550
4000
][550];
int edge[550][550];
int d[4][2]={{-1, 0}, {0,-1}, {1, 0}, {0, 1}};
int flag[550], link[550];
bool dfs(int x){
int y;
for(y=1; y<=len; y++){
if(edge[x][y] && !flag[y]){
flag[y]=1;
if(link[y]==0 || dfs(link[y])){
link[y] = x;
return true;
}
}
}
return false;
}
int main(){
int T, i, j, k;
scanf("%d", &T);
while(T--){
//注意初始化
memset(link, 0, sizeof(link));
memset(Map, 0, sizeof(Map));
memset(edge, 0, sizeof(edge));
scanf("%d %d%*c", &n, &m);
char c;
len=0;
for(i=1; i<=n; i++){
for(j=1; j<=m; j++){
scanf("%c", &c);
if(c=='*'){
Map[i][j] = ++len;//给每个城市编号, Map存每个城市的编号
}
}
getchar();
}
//建图 -> 拆点
int x, y;
for(i=1; i<=n; i++){
for(j=1; j<=m; j++){
if(Map[i][j]){
int id = Map[i][j];
for(k=0; k<4; k++){//东南西北连边中~~~
x = i+d[k][0];
y = j+d[k][1];
int idd = Map[x][y];
if(Map[x][y]) edge[id][idd]=1;
}
}
}
}
ans=0;
for(i=1;i<=len; i++){
memset(flag, 0, sizeof(flag));
if(dfs(i)) ans++;
}
//len是总点数, ans是上图求出的最大匹配数, 应当除以2才是原集合的最大匹配数
printf("%d\n", len-ans/2);
}
return 0;
}
相关文章推荐
- poj 3020 Antenna Placement(最小路径覆盖 + 匈牙利算法)
- POJ 3020 Antenna Placement(匈牙利算法—最小路径覆盖)
- poj3020 匈牙利算法+公式:二分无向图的最小路径覆盖 = 顶点数 - 最大二分匹配数 / 2
- poj 3020 Antenna Placement(二分图+最小路径覆盖)
- POJ 3020:Antenna Placement(无向二分图的最小路径覆盖)
- POJ 3020 Antenna Placement(无向二分图的最小路径覆盖)
- HDOJ---1151 Air Raid[匈牙利算法:最小路径覆盖数=原图顶点数–二分图最大匹配数]
- poj 3020 二分图(奇偶图) 最小路径覆盖
- Poj 3020 Antenna Placement (二分图最小路径覆盖)
- POJ-1422-Air Raid-求最小路径覆盖(匈牙利算法)
- POJ 1422 Air Raid (二分图最小点集覆盖 匈牙利算法)
- poj 3020(二分图最小路径覆盖,拆点)
- POJ 3020 Antenna Placement ,二分图的最小路径覆盖
- POJ - 3020 Antenna Placement 二分图 最小路径覆盖
- 彻底搞定二分图的匈牙利算法,最大匹配数(最小覆盖数)、最大独立数、最小路径覆盖
- 【二分图+最小路径覆盖】北大 poj 3020 Antenna Placement
- 二分图最小路径覆盖——POJ 3020
- poj 3020 最小边覆盖与最大匹配 匈牙利算法
- POJ-1947-Asteroids-求最小点覆盖数(二分图-匈牙利算法)
- hdu1151(二分图+最小路径覆盖数+匈牙利算法)