HDOJ 1045 Fire Net (二分图匹配)

题意:给定一个n*n的棋盘,棋盘中的'X’代表障碍物,'.'代表空地,问在空地上最多放多少车,使得它们不会互相攻击。

分析:由于n比较小,应该可以直接暴力,这里用的二分匹配的方法。

建图:先扫描行,连通的格子看成一个结点,这样可以得到二分图的X部,再同样扫描列,得到Y部,有公共方格的结点连边,然后求最大匹配就是结果。

正确性分析:扫描行得到的结点之间不可能有公共方格,所以X部的结点内部没有连边,同理Y部的结点内部结点没有连边,所以建立的图是二部图。每个结点内最多只能放一个车,有公共方格的结点最多只能选取其中一个放车,这样就得到一个最大匹配的模型。

View Code
#include <stdio.h>

#include <string.h>

#define N 16

char map[5][5];

int idx[5][5],idy[5][5];

int n;

int g[N][N];

int x[N],y[N],cnt1,cnt2;

int vis[N];

int path(int u)

{

    for(int v=1;v<=cnt2;v++)    if(g[u][v] && !vis[v])

    {

        vis[v]=1;

        if(y[v]==-1 || path(y[v]))

        {

            x[u]=v;

            y[v]=u;

            return 1;

        }

    }

    return 0;

}

int maxmatch()

{

    int i,ret=0;

    memset(x,-1,sizeof(x));

    memset(y,-1,sizeof(y));

    for(i=1;i<=cnt1;i++)

    {

        memset(vis,0,sizeof(vis));

        if(x[i]==-1)    ret+=path(i);

    }

    return ret;

}

void build()

{

    int i,j;

    cnt1=0;

    for(i=0;i<n;i++)

    {

        for(j=0;j<n;j++)    if(map[i][j]=='.')

        {

            if(j==0 || map[i][j-1]!='.')    cnt1++;

            idx[i][j]=cnt1;

        }

    }

    cnt2=0;

    for(j=0;j<n;j++)

    {

        for(i=0;i<n;i++)    if(map[i][j]=='.')

        {

            if(i==0 || map[i-1][j]!='.')    cnt2++;

            idy[i][j]=cnt2;

        }

    }

    memset(g,0,sizeof(g));

    for(i=0;i<n;i++)

    {

        for(j=0;j<n;j++)    if(map[i][j]=='.')  g[idx[i][j]][idy[i][j]]=1;

    }

}

int main()

{

    int i;

    while(scanf("%d",&n),n)

    {

        for(i=0;i<n;i++)    scanf("%s",map[i]);

        build();

        printf("%d\n",maxmatch());

    }

    return 0;

}

 

你可能感兴趣的:(net)