poj3020-Antenna Placement(最小路径覆盖问题,最大匹配)

题目来源:http://poj.org/problem?id=3020

题意

为城镇安装无线网络(WI-FI),给出一个矩阵,矩阵里的’*’代表房子,然后’o’代表空地,也就是不是房子,然后一个无线覆盖的范围是挨着的两个房子(不可以斜着),然后问,最少需要多少个无线。。。

思路

这道题采用了拆点的思想,然后给重新分成两部分的点集加上关系(挨着的),然后就是利用匈牙利匹配得到最大匹配,利用公式:最小路径覆盖=节点数-最大匹配。

代码

//vis数组的大小是拆点之后的大小。
#include
#include
#include
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();
    }
}

你可能感兴趣的:(ACM竞赛,【图论】--二分图匹配,ACM的进程)