poj 2226 Muddy Fields(最小覆盖点+构图)

http://poj.org/problem?id=2226

Muddy Fields
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 9022   Accepted: 3348

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.
 
题目大意:用宽度为1长度不限的木板将水洼‘*’盖住而不盖住草‘.'
 
这道题,构图确实比比较巧妙,如果有连续的水洼,假设是横排的,那么这几个连续的水洼可以拿一个板子来覆盖,同样,如果竖排也有连续的水洼,那么也可以拿一个板子来覆盖。这样,当一个水洼既可以拿横着的板子,也可以拿竖着的板子覆盖时,就是相交了。那么这个交线就代表了一个水洼,它既可以被横着盖,也可以被竖着盖。现在我们把所有横排的水洼作为1个水洼需要1个木板,竖着的也同理
 
有两种覆盖的方法,一种为横着盖一种为竖着盖覆盖后可转化为下图形式
横着盖:(图中数字表示用的是第几块木板)
1.2.
.333
444.
. . 5.
将这些点加入到X序列中
 
竖着盖:
1.2.
.324
532.
. . 2.
将这些点加入到Y序列中
 
将图中水洼进行编号一共有九个水洼
1.2.
.345
678.
. . 9.
 
9号水洼(5, 2)表示九号水洼可由横着的5号木板覆盖也可以由竖着的2号木板覆盖,5号木板和2号木板之间就有一条线
这样就组成一个二分图
X        Y
1        1
2        2
3        3
4        4
5        5
用最少的点把所有的边连起来就是最小覆盖点
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#define N 1100

int G[N][N], vis[N], used[N];
char maps[N][N];
int m, n, x, y;

bool Find(int u)
{
    int i;
    for(i = 1 ; i <= y ; i++)
    {
        if(!vis[i] && G[u][i])
        {
            vis[i] = 1;
            if(!used[i] || Find(used[i]))
            {
                used[i] = u;
                return true;
            }
        }
    }
    return false;
}

void Build()//构图
{
    int i, j, a[N][N] , b[N][N];
    x = y = 0;
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    for(i = 1 ; i <= m ; i++)
    {
        for(j = 1 ; j <= n ; j++)
        {
            if(maps[i][j] == '*')
            {
                if(maps[i][j - 1] == '*')
                    a[i][j] = a[i][j - 1];
                else
                    a[i][j] = ++x;
            }
        }
    }//木板横着放
    for(i = 1 ; i <= m ; i++)
    {
        for(j = 1 ; j <= n ; j++)
        {
            if(maps[i][j] == '*')
            {
                if(maps[i - 1][j] == '*')
                    b[i][j] = b[i - 1][j];
                else
                    b[i][j] = ++y;
                G[a[i][j]][b[i][j]] = 1;
            }
        }
    }//木板竖着放
}

int main()
{
    int i, j, ans;
    while(~scanf("%d%d", &m, &n))
    {
        ans = 0;
        memset(G, 0, sizeof(G));
        for(i = 1 ; i <= m ; i++)
           {
               getchar();
               for(j = 1 ; j <= n ; j++)
               {
                   scanf("%c", &maps[i][j]);
               }
           }
        Build();
        memset(used, 0, sizeof(used));
        for(i = 1 ; i <= x ; i++)//X集合中的点与Y集合中的点找最大匹配
        {
            memset(vis, 0, sizeof(vis));
            if(Find(i))
                ans++;
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2015-08-10 09:51  午夜阳光~  阅读(916)  评论(0编辑  收藏  举报