题目链接: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; }