poj2226Muddy Fields 二分匹配之最小点覆盖

//给r*c的 field ,有的地方有水,用宽度为1,长度任意的木板将这些有水的地方,
//遮住,木板可以相互叠加,木板不能遮住有草的地方
//可以每行中的连续的格子看成一个点xi,每一列中连续的格子看成一个点yj
//将每一个有水的格子看成一条边连接对应的xi , yj
//那么其最小点覆盖即为答案
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std ;
const int maxn = 2110 ;
int map[maxn][maxn] ;
int id[maxn][maxn] ;
char str[maxn][maxn] ;
int match[maxn] ;
int vis[maxn] ;
int n , len_1 , len_2 , m;
bool find(int st)
{
    for(int i = 1;i <= len_2;i++)
    if(!vis[i] && map[st][i])
    {
        vis[i] = 1 ;
        if(match[i] == -1 || find(match[i]))
        {
            match[i] = st;
            return true ;
        }
    }
    return false ;
}

int main()
{
    //freopen("in.txt" ,"r" ,stdin) ;
    while(~scanf("%d %d" , &n , &m))
    {
        memset(map , 0 , sizeof(map)) ;
        memset(match , -1 , sizeof(match)) ;
        len_1 = 1 ;len_2 = 1;
        for(int i = 1;i <= n;i++)
        {
            scanf("%s" , &str[i][1]) ;
            for(int j = 1;j <= m;j++)
            {
                if(str[i][j] == '*')
                id[i][j] = len_1;
                if(str[i][j] == '.' && str[i][j-1] == '*')
                len_1++;
            }
            if(str[i][m] != '.')len_1++;
        }
        for(int j = 1;j <= m;j++)
        {
            for(int i = 1;i <= n;i++)
            {
               if(str[i][j] == '*')
               map[id[i][j]][len_2] = 1 ;
               if(str[i][j] == '.' && str[i-1][j] == '*')
               len_2++ ;
            }
            if(str[n][j] != '.')
            len_2++;
        }
        int ans = 0 ;
        for(int i = 1;i <= len_1 ;i++)
        {
            memset(vis ,0 , sizeof(vis)) ;
            if(find(i))
            ans++ ;
        }
        cout<<ans<<endl;
    }
}





















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