poj2226

这道题又是理解了老半天。。。才看懂,我们把行联通块列联通块放在左右两侧,有交点就连边。然后求一下最小覆盖,这个含义是什么呢,我们知道我们知道其实最小覆盖可以理解为点来覆盖边,边覆盖完意味着什么呢,就是原来的图被完全覆盖了(最好可以画画看)反正我是想不出这么牛的建模的。。。还是太弱,,,

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>

#define N 55
#define M N*N
using namespace std;

int n,ny,nx,m;
int map[M][M];
int cx[M],cy[M],mark[M];

char str[N][N];

int map_x[N][N],map_y[N][N];

int path(int u)
{
    int j;
    for(j=1;j<=ny;j++)
    {
        if(map[u][j]&&!mark[j])
        {
            mark[j]=1;
            if(cy[j]==-1||path(cy[j]))
            {
                cx[u] = j;
                cy[j] = u;
                return 1;
            }
        }
    }
    return 0;
}

int maxMatch()  //求最小覆盖
{
    memset(cx,-1,sizeof(cx));
    memset(cy,-1,sizeof(cy));
    int i;
    int res = 0;
    for(i=1;i<=nx;i++)
    {
        if(cx[i]==-1)
        {
            memset(mark,0,sizeof(mark));
            res+=path(i);
        }
    }
    return res;
}

void getMap()
{
    memset(map,0,sizeof(map));
    memset(map_x,0,sizeof(map_x));
    memset(map_y,0,sizeof(map_y));
    int i,j;
    int flag;
    nx=ny=0;
    for(i=0;i<n;i++)  //横向分区域
    {
        for(j=0;j<m;j++)
        {
            flag = 0;
            while(j<m&&str[i][j]=='*')
            {
                if(!flag)   ++nx;
                map_x[i][j] = nx;
                j++;
                flag = 1;
            }
        }
    }

    for(j=0;j<m;j++)  //纵向分区
    {
        for(i=0;i<n;i++)
        {
            flag = 0;
            while(i<n&&str[i][j]=='*')
            {
                if(!flag)   ++ny;
                flag = 1;
                map_y[i][j] = ny;
                i++;
            }
        }
    }

    for(i=0;i<n;i++)  //横向纵向区域连接
    {
        for(j=0;j<m;j++)
        {
            int x = map_x[i][j];
            int y = map_y[i][j];
            if(x&&y)
            {
                map[x][y] = 1;  //得到二分map图,然后进行最小覆盖
            }
        }
    }
}


int main()
{
    int i;
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
    {
        scanf("%s",str[i]);
    }
    getMap();
    printf("%d\n",maxMatch());
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值