首页 > 代码库 > POJ 2226 Muddy Fields(二分匹配 巧妙的建图)

POJ 2226 Muddy Fields(二分匹配 巧妙的建图)

题目链接:http://poj.org/problem?id=2226


Description

Rain has pummeled the cows‘ field, a rectangular grid of R rows and C columns (1 <= R <= 50, 1 <= C <= 50). While good for the grass, the rain makes some patches of bare earth quite muddy. The cows, being meticulous grazers, don‘t want to get their hooves dirty while they eat. 

To prevent those muddy hooves, Farmer John will place a number of wooden boards over the muddy parts of the cows‘ field. Each of the boards is 1 unit wide, and can be any length long. Each board must be aligned parallel to one of the sides of the field. 

Farmer John wishes to minimize the number of boards needed to cover the muddy spots, some of which might require more than one board to cover. The boards may not cover any grass and deprive the cows of grazing area but they can overlap each other. 

Compute the minimum number of boards FJ requires to cover all the mud in the field.

Input

* Line 1: Two space-separated integers: R and C 

* Lines 2..R+1: Each line contains a string of C characters, with ‘*‘ representing a muddy patch, and ‘.‘ representing a grassy patch. No spaces are present.

Output

* Line 1: A single integer representing the number of boards FJ needs.

Sample Input

4 4
*.*.
.***
***.
..*.

Sample Output

4

Hint

OUTPUT DETAILS: 

Boards 1, 2, 3 and 4 are placed as follows: 
1.2. 
.333 
444. 
..2. 
Board 2 overlaps boards 3 and 4.

Source

USACO 2005 January Gold


题意:农夫John的养牛场,是一个R 行C 列的矩形,一场大雨后,养牛场低洼的地方都有了积水。John 的牛都很娇贵的,他们吃草的时候,不想把他们的蹄子给弄脏了。为了不让牛儿们把它们的蹄子弄脏,John 决定把有水的地方铺上木板。他的木板是宽度为1,长度没有限制的。

他想用最少数目的木板把所有有水的低洼处给覆盖上,前提是木板不能覆盖草地,但是可以重叠。

这道题,构图确实比比较巧妙,如果有连续的低洼处,假设是横排的,那么这几个连续的低洼处可以拿一个板子来覆盖,同样,如果竖排也有连续的低洼处,那么也可以拿一个板子来覆盖。这样,当一个低洼处既可以拿横着的板子,也可以拿竖着的板子覆盖时,就是相交了。那么这个交线就代表了一个低洼处,它既可以被横着盖,也可以被竖着盖。现在我们把所有横排的低洼处作为left(连续的低洼处作为1个板),竖着的也同理,以例题如下表式:
Sample:
4 4
*.*.
.***
***.
..*.

把行里面连在一起的坑连起来视为一个点,即一块横木板,编上序号,Sample则转化为:

1 0 2 0
0 3 3 3
4 4 4 0
0 0 5 0

把这些序号加入X集合,再按列做一次则为:

1 0 4 0
0 3 4 5
2 3 4 0
0 0 4 0

同样加入Y集合,一个坑只能被横着的或者被竖着的木板盖住,将原图的坑的也标上不同的序号,一共九个坑

1 . 2 .
. 3 4 5
6 7 8 .
. . 9 .

图中的2号低洼处既可以拿横着的2号板,也可以拿竖着的4号板来覆盖,那么2号版和四号板之间就有一条边,边实际表示了低洼处,例如2号低洼处的边为{2,4},可以理解为2号低洼处可以由2号板或4号板覆盖。用最少的点把所有的边连起来,这样就是最小点覆盖。

以上来自: http://hi.baidu.com/onlys_c/blog/item/9781e0dd858f2fd28d102919.html


代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 1017;
int LN, RN;
int g[MAXN][MAXN];
char s[MAXN][MAXN];
int U[MAXN][MAXN], V[MAXN][MAXN];
int linker[MAXN];
bool used[MAXN];

int dfs(int L)
{
    for(int R = 1; R <= RN; R++)
    {
        if(g[L][R] && !used[R])
        {
            used[R] = true;
            if(linker[R]==-1 || dfs(linker[R]))
            {
                linker[R] = L;
                return 1;
            }
        }
    }
    return 0;
}
int hungary()
{
    int res = 0;
    memset(linker,-1,sizeof(linker));
    for(int L = 1; L <= LN; L++)
    {
        memset(used,false,sizeof(used));
        if(dfs(L))
            res++;
    }
    return res;
}
int main()
{
    int R, C;
    while(~scanf("%d%d",&R,&C))
    {
        int u = 0, v = 0;
        memset(g,0,sizeof(g));
        for(int i = 1; i <= R; i++)
        {
            for(int j = 1; j <= C; j++)
            {
                cin>>s[i][j];
            }
        }
        for(int i = 1; i <= R; i++)
        {
            for(int j = 1; j <= C; j++)
            {
                if(s[i][j] == '*')
                {
                    u++;
                    while(j <= C && s[i][j] == '*')
                    {
                        U[i][j] = u;
                        j++;
                    }
                }
            }
        }
        for(int j = 1; j <= C; j++)
        {
            for(int i = 1; i <= R; i++)
            {
                if(s[i][j] == '*')
                {
                    v++;
                    while(i <= R && s[i][j] == '*')
                    {
                        V[i][j] = v;
                        i++;
                    }
                }
            }
        }
        for(int i = 1; i <= R; i++)
        {
            for(int j = 1; j <= C; j++)
            {
                if(s[i][j] == '*')
                {
                    g[U[i][j]][V[i][j]] = 1;
                }
            }
        }
        LN = u, RN = v;
        int ans = hungary();
        printf("%d\n",ans);
    }
    return 0;
}


POJ 2226 Muddy Fields(二分匹配 巧妙的建图)