POJ2226 Muddy Fields【二分图最小点覆盖】

来源:互联网 发布:linux安全加固方案 编辑:程序博客网 时间:2024/04/29 12:00

题目链接:

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


题目大意:

有一个r行c列的方格组成的田地。里边有若干个方格充满泥水,其余的方格是草。要用宽度为1、长度

不限的长木板把充满泥水的方格覆盖掉,但不能覆盖草地,同时只能按行覆盖或是按列覆盖,不能斜着

覆盖。问:最少要用多少木板。


思路:

这道题感觉很难想。看了看网上的题解,居然很巧妙的构造了二分图来求解,很是精妙。我们把同一行

一段连续的泥水方格作为一个顶点,把这些点作为二分图的一个集合,再把同一列一段连续的泥水方格

作为一个顶点,把这些点作为二分图的另一个集合。如果两个集合的点有相交,就建立一条边。两个集

合相交说明相交的地方为原图上的一个泥水方格,边和泥水方格就变成了一一对应的关系。如果选择了

一个边(木板),则与该边(木板)关联的所有泥方格都会被覆盖掉。那么问题就变成了求解二分图最小点集

覆盖。二分图最小点集覆盖 = 二分图最大匹配,用匈牙利算法来解决。

这道题有一个地方要注意,就是二分图点的个数问题。考虑到原图规模是55*55,而连续的泥水方格当

一个点,现在为了求出最多有多少个点,假设所有的泥水方格都不连续,即每个泥水方格都是独立的,

周围都是草地。则最多有23*23+22*22 = 1013个点,即为二分图一个集合点的个数。


AC代码:

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;const int MAXN = 1016;bool Map[MAXN][MAXN],Mask[MAXN];int NX,NY;int cx[MAXN],cy[MAXN];char G[60][60];int fa[60][60],fb[60][60];int FindPath(int u){    for(int i = 0; i < NY; ++i)    {        if(Map[u][i] && !Mask[i])        {            Mask[i] = 1;            if(cy[i] == -1 || FindPath(cy[i]))            {                cy[i] = u;                cx[u] = i;                return 1;            }        }    }    return 0;}int MaxMatch(){    for(int i = 0; i < NX; ++i)        cx[i] = -1;    for(int i = 0; i < NY; ++i)        cy[i] = -1;    int res = 0;    for(int i = 0; i < NX; ++i)    {        if(cx[i] == -1)        {            for(int j = 0; j < NY; ++j)                Mask[j] = 0;            res += FindPath(i);        }    }    return res;}int main(){    int N,M;    while(~scanf("%d%d",&N,&M))    {        for(int i = 0; i < N; ++i)            scanf("%s",G[i]);        memset(fa,0,sizeof(fa));        memset(fb,0,sizeof(fb));        memset(Map,0,sizeof(Map));        int n = 0;        for(int i = 0; i < N; ++i)        {            int sum = 0;            for(int j = 0; j < M; ++j)            {                if(G[i][j] == '*')                {                    fa[i][j] = n;                    if(G[i][j+1]!='*')                        n++;                }            }        }        int m = 0;        for(int i = 0; i < M; ++i)        {            for(int j = 0; j < N; ++j)            {                if(G[j][i] == '*')                {                    fb[j][i] = m;                    if(G[j+1][i]!= '*')                        m++;                }            }        }        for(int i = 0; i < N; ++i)            for(int j = 0; j < M; ++j)                if(G[i][j] == '*')                    Map[fa[i][j]][fb[i][j]] = 1;        NX = n,NY = m;        printf("%d\n",MaxMatch());    }    return 0;}


0 0
原创粉丝点击