POJ_2226 Muddy Fields(最小点覆盖)

Muddy Fields

Time Limit: 1000MS
Memory Limit: 65536K
Problem 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.endpoints of the other one.

Output

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

Sample Input

4 4
* .*.
.***
***.
…*.

Sample Output

4

题意

有一个n*m的区域,每一个格子是草地或者泥坑,现在有宽度为1,长度任意的木板。木板可以覆盖泥坑,但不能覆盖草地,求最少需要多少块木板能覆盖所有泥坑。

题解:

因为泥坑可以被多次覆盖,当木板横放或者竖放时,木板的长应尽量的长,这样才能覆盖更多的泥坑。对于泥坑而言,每个泥坑至少需要被横放或竖放的木板覆盖一次。所以可以将横放的木板和竖放的木板看着二分图的两部分(一块木板代表一个点),将每个泥坑作为一条边,然后求二分图的最小点覆盖。
1.建图:只考虑横放,求每个泥坑属于哪块木板,记 i d 1 id1 id1,只考虑竖放,求每个泥坑属于哪块木板,记 i d 2 id2 id2,对于泥坑,连边 i d 1 − > i d 2 id1->id2 id1>id2
2.求二分图最小点覆盖,二分图最小点匹配=二分图最大匹配。匈牙利或者网络流求最大匹配即可。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<set>
#include<queue>
#include<stack>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
 
using namespace std;
typedef long long LL;   
typedef pair<int, int> P;
const int maxn = 2100;
const int mod = 1000000007;
char str[56][56];
int n, m, xnum, ynum, id1[56][56], id2[56][56];
int vis[maxn], py[maxn];
vector<int> g[maxn];
void getmap(int n, int m);
int xiongya();
bool match(int u);

int main()
{
    int n, m, i, j;
    scanf("%d %d", &n, &m);
    for(i=0;i<n;i++)
        scanf(" %s", str[i]);
    getmap(n, m);
    int ans = xiongya();
    printf("%d\n", ans);
    return 0;
}
//匈牙利算法,求二分图最大匹配
int xiongya()
{
    int ans = 0, i, j;
    memset(py, -1, sizeof(py));
    for(i=1;i<=xnum;i++)
    {
        memset(vis, 0, sizeof(vis));
        if(match(i))ans++;
    }
    return ans;
}

bool match(int u)
{
    for(int i=0;i<g[u].size();i++)
        if(!vis[g[u][i]])
        {
            vis[g[u][i]] = 1;
            if(py[g[u][i]] == -1 || match(py[g[u][i]]))
            {
                py[g[u][i]] = u;
                return true;
            }
        }
    return false;
}
//建图
void getmap(int n, int m)
{
    int i, j, k;
    xnum = ynum = 0;
    memset(id1, -1, sizeof(id1));
    memset(id2, -1, sizeof(id2));
    for(i=0;i<n;i++)
        for(j=0;j<m;j++)
            if(str[i][j] == '*' && id1[i][j] == -1)
            {
                id1[i][j] = ++xnum;
                k = j+1;
                while(k<m && str[i][k] == '*')
                {
                    id1[i][k] = id1[i][j];
                    k++;
                }
            }
    for(i=0;i<n;i++)
        for(j=0;j<m;j++)
            if(str[i][j] == '*' && id2[i][j] == -1)
            {
                id2[i][j] = ++ynum;
                k = i+1;
                while(k<n && str[k][j] == '*')
                {
                    id2[k][j] = id2[i][j];
                    k++;
                }
            }
    for(i=0;i<n;i++)
        for(j=0;j<m;j++)
            if(str[i][j] == '*')
                g[id1[i][j]].push_back(id2[i][j]);
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值