POJ2226 Muddy Fields

本文介绍了一种利用二分图和匈牙利算法解决牧场覆盖问题的方法。通过将泥泞点抽象为二分图,并使用匈牙利算法找到最小覆盖数。附带AC代码供读者参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题目算是二分图中比较难的一道,明明知道是二分图问题,应该用匈牙利算法解决,可是看了半天也没发现二分图的特点在哪里,后来看了高人的博客才明白要把二维图抽象出来,将每一道x方向相连的“*”看做一个点,所有x方向的“点”构成一个集合,同理所有Y方向的“点”构成另外一个集合,若横向的一行和纵向的一列有交点则将两个“点”连起来,这样就是一个二分图了。真心佩服第一个想到要这样做的大神。
题目链接:http://poj.org/problem?id=2226
题目大意:有一个R*C大小的牧场,下雨过后一些点变得很泥泞,为了防止把牛的蹄子弄脏,牧场主决定要在泥泞的点上覆盖木板,木板宽一个单位,但是可以任意长度,求最少需要多少块木板。
解题思路:见如上分析,将图抽象成二部图,再利用匈牙利算法。

//AC代码:
#include <iostream>
#include <string.h>
using namespace std;
#define MAX 1000
bool used[MAX];
int linked[MAX];
int g[MAX][MAX];
int temp[MAX][MAX];
char graph[MAX][MAX];
int r,c;
int indexr,indexc;

void build()
{
    memset(g,0,sizeof(g));
    memset(temp,0,sizeof(temp));
    int flag=0;
    indexr=0;
    indexc=0;
    for(int i=1;i<=r;i++)
    {
        flag=0;
        for(int j=1;j<=c;j++)
        {
            if(graph[i][j]=='*'&&flag==0){indexr++;flag=1;}
            if(graph[i][j]=='*'&&flag==1)temp[i][j]=indexr;
            if(graph[i][j]=='.')flag=0;
        }
    }
    for(int j=1;j<=c;j++)
    {
        flag=0;
        for(int i=1;i<=r;i++)
        {
            if(graph[i][j]=='*'&&flag==0){indexc++;flag=1;}
            if(graph[i][j]=='*'&&flag==1)g[temp[i][j]][indexc]=1;
            if(graph[i][j]=='.')flag=0;
        }
    }
}

bool dfs(int u)
{
    int v;
    for(v=1;v<=indexc;v++)
    {
        if(g[u][v]&&!used[v])
        {
            used[v] = true;
            if(linked[v]==-1||dfs(linked[v]))
            {
                linked[v] = u;
                return true;
            }
        }
    }
    return false;
}

int hungry()
{
    int u;
    int res=0;
    memset(linked,-1,sizeof(linked));
    for(u=1;u<=indexr;u++)
    {
        memset(used,0,sizeof(used));
        if(dfs(u))res++;
    }
    return res;
}

int main()
{
    while(cin>>r>>c)
    {
        for(int i=1;i<=r;i++)
        {
            for(int j=1;j<=c;j++)
            {
                cin>>graph[i][j];
            }
        }
        build();
        cout<<hungry()<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值