poj 2226

题意:给出一个矩阵 , 每个点代表青草或者泥泞的路 , 问你最少要多少块木板(宽度为一个点的宽度 , 长度任意)才能把这些泥泞的路都盖住 , 并且不能把草盖住 , 木板可以重合 。

这题要是没加(不能把草盖住)这个条件 , 那么就是普通的最小路径覆盖 。
然而加了这个题之后 , 还是用最小路径覆盖 , 只不过要重新建过图。

最小路径覆盖 = 原图节点数 - 建图后的最大匹配 。
建图:分两步 , 1、从行开始 , 对么个点就行编号 , 如果在同一行并且相邻 , 那么就标记为一个编号 。
                              2、从列开始 , 做法和1一样 , 行跟列是分别单独进行的 。
之后把行构成的点 , 看成是X点集合 , 列看成是Y点集合 , 再根据原图每个点的行跟列进行连接 , 就可以够成一个二分图 。
最近就只要用最下路径覆盖就能求出了 。

代码:




#include
#include
#include
#include
#include
#include
using namespace std;

const int MAXN = 120;
int n , m ,  pre[2500] , lx[MAXN][MAXN] , ly[MAXN][MAXN];
vectorgrap[2500];
bool s[2500];
int x , y;

void init()
{
    for(int i = 0; i <= n; i++)
        grap[i].clear();
    memset(lx , 0 , sizeof(lx));
    memset(ly ,0 , sizeof(ly));
}

bool can(int u)
{
    for(int i = 0 ; i < grap[u].size(); i++)
    {
        int v = grap[u][i] ;
        if(!s[v])
        {
            s[v] = true;
            if(pre[v] == -1 || can(pre[v]))
            {
                pre[v] = u;
                return true;
            }
        }
    }
    return false;
}

int km()
{
    int sum = 0;
    memset(pre , -1 , sizeof(pre));
    for(int i = 1; i < x; i++)
    {
        memset(s , false , sizeof(s));
        if(can(i))  sum += 1;
    }
    return sum;
}

int main()
{
    while(scanf("%d %d" , &n , &m) != EOF)
    {
        getchar();
        init();
        int i  ,j ;
        x = 1 , y = 1;
        char cy[100][100];
        for(i = 0 ; i < n; i++)
        {
            scanf("%s" , cy[i]);
            for(j = 0 ; j < m ; j++)
                if(cy[i][j] == '*')
                {
                    for( ; j < m; j++)
                    {
                        if(cy[i][j] == '*')  lx[i][j] = x;
                        else {x += 1; break;}
                    }
                    if(j == m)  x += 1;
                }
        }
        for(i = 0 ; i < m; i++)
        {
            for(j = 0 ; j < n; j++)
                if(cy[j][i] == '*')
                {
                    for(; j < n; j++)
                    {
                        if(cy[j][i] == '*')  ly[j][i] = y;
                        else {y += 1; break;}
                    }
                    if(j == n)  y += 1;
                }
        }
   
        for(i = 0; i < n; i++)
            for(j = 0 ; j < m; j++)
            {
                if(lx[i][j])  grap[lx[i][j]].push_back(ly[i][j]) ;
            }
        cout<<km()<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值