【HDOJ 1045】Fire Net--二分图

【HDOJ 1045】Fire Net

数据量很小 dfs暴力可过 不过最近在学二分图 想了想二分图的做法
根据题目要求 不能让同行或者同列出现一个以上的车(无墙状态下 因此根据行 列 构建二分图 每行上联通的一段区间标为同一个号 列同理标注 然后再遍历 发现有交界时将行与列联通 最后进行一次二分最大匹配即可

代码如下:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

bool mp[17][17],vis[17];
int idx[5][5],idy[5][5];
char qp[5][6];
int n,link[17],p1,p2;

void Sd()
{
    int i,j,k;
    for(p1 = 0,i = 1; i <= n; ++i)
    {
        for(j = 1; j <= n; ++j)
        {
            if(j == 1 || qp[i][j-1] == 'X') p1++;
            idx[i][j] = p1;
        }
    }

    for(p2 = 0,j = 1; j <= n; ++j)
    {
        for(i = 1; i <= n; ++i)
        {
            if(i == 1 || qp[i-1][j] == 'X') p2++;
            idy[i][j] = p2;
        }
    }

    for(i = 1; i <= n; ++i)
    {
        for(j = 1; j <= n; ++j)
        {
            if(qp[i][j] == '.') mp[idx[i][j]][idy[i][j]] = 1;
        }
    }

}

bool can(int p)
{
    int i;
    for(i = 0; i <= p2; ++i)
    {
        if(!vis[i] && mp[p][i])
        {
            vis[i] = true;
            if(link[i] == -1 || can(link[i]))
            {
                link[i] = p;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    int i,j,cnt,sum;
    while(~scanf("%d",&n) && n)
    {
        cnt = 0;
        for(i = 1; i <= n; ++i)
            scanf("%s",qp[i]+1);
        memset(mp,0,sizeof(mp));

        Sd();

        memset(link,-1,sizeof(link));
        for(i = 0; i <= p1; ++i)
        {
            memset(vis,0,sizeof(vis));
            if(can(i)) cnt++;
        }
        printf("%d\n",cnt);
    }
    return 0;
}

你可能感兴趣的:(二分图)