您的位置:首页 > 其它

POJ 3020(二分图之最小路径覆盖)

2016-01-24 20:48 375 查看
题目链接:http://poj.org/problem?id=3020

题意:给出n行m列字符,‘*’表示城市,‘o’表示空地,在城市建立无线覆盖,每个可以覆盖到相邻的城市,并且已被覆盖的城市不能被再次覆盖,求能覆盖所有的点的最少的边。

思路:

这题是最小路径覆盖问题,利用一个定理:

最小路径覆盖=顶点数-最大匹配数

题目的难点应该在于如何建图,建立二分图的模型。

先给每个城市编号,以城市作为点集,建立二分图的模型。

具体实现代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

const int INF=0x3f3f3f3f;
const int maxn=505;
int T,n,m;
int map[maxn][maxn];
int line[maxn][maxn];
int girl[maxn];
bool used[maxn];
int cnt;

int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};

bool dfs(int x){
for(int i=1;i<=cnt;i++){
if(line[x][i]&&!used[i]){
used[i]=1;
if(!girl[i]||dfs(girl[i])){
girl[i]=x;
return true;
}
}
}
return false;
}

int hungary(){
int ans=0;
memset(girl,0,sizeof(girl));
for(int i=1;i<=cnt;i++){
memset(used,0,sizeof(used));
if(dfs(i))
ans++;
}
return ans;
}

int main(){
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
#endif
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
memset(line,0,sizeof(line));
memset(map,0,sizeof(map));
char tmp[100];
cnt=1;
for(int i=1;i<=n;i++){
scanf("%s",tmp);
for(int j=0;j<m;j++){
if(tmp[j]=='*')
map[i][j+1]=cnt++;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(map[i][j]){
for(int k=0;k<4;k++){
int x=i+dx[k];
int y=j+dy[k];
if(map[x][y]){
line[map[i][j]][map[x][y]]=1;
}
}
}
}
}
cnt--;
int ans=cnt-hungary()/2;
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: