题目来源:http://poj.org/problem?id=3020
题意
为城镇安装无线网络(WI-FI),给出一个矩阵,矩阵里的’*’代表房子,然后’o’代表空地,也就是不是房子,然后一个无线覆盖的范围是挨着的两个房子(不可以斜着),然后问,最少需要多少个无线。。。
思路
这道题采用了拆点的思想,然后给重新分成两部分的点集加上关系(挨着的),然后就是利用匈牙利匹配得到最大匹配,利用公式:最小路径覆盖=节点数-最大匹配。
代码
//vis数组的大小是拆点之后的大小。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=40+10;
char str[maxn][maxn];
int num[maxn][maxn],mp[maxn*maxn][maxn*maxn];
int pre[maxn*maxn],vis[maxn*maxn];
int n,m,tot;
void init()
{
tot=0;
scanf("%d%d",&n,&m);
getchar();
memset(num,0,sizeof(num));
memset(mp,0,sizeof(mp));
for(int i=1;i<=n;i++)
{
scanf("%s",str[i]+1);
for(int j=1;j<=m;j++)
{
if(str[i][j]=='*')
num[i][j]=++tot;
}
}
}
void deal()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!num[i][j]) continue;
if(i!=1&&num[i-1][j]) mp[num[i][j]][num[i-1][j]]=1;
if(i!=n&&num[i+1][j]) mp[num[i][j]][num[i+1][j]]=1;
if(j!=1&&num[i][j-1]) mp[num[i][j]][num[i][j-1]]=1;
if(j!=m&&num[i][j+1]) mp[num[i][j]][num[i][j+1]]=1;
}
}
}
int dfs(int i)
{
for(int j=1;j<=tot;j++)
{
if(mp[i][j]&&!vis[j])
{
vis[j]=1;
if(pre[j]==-1||dfs(pre[j]))
{
pre[j]=i;
return 1;
}
}
}
return 0;
}
void solve()
{
deal();
int ret=0;
memset(pre,-1,sizeof(pre));
for(int i=1;i<=tot;i++)
{
memset(vis,0,sizeof(vis));
ret+=dfs(i);
}
printf("%d\n",tot-ret/2);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
solve();
}
}