poj2226(最小点覆盖)

  这题和poj3041有点类似,但是建图方式却不是一样的,因为这题要求放的板子不能覆盖了草。

样例是这样的,下面就讲讲怎么建图

4 4
*.*.
.***
***.
..*.

把行里面连在一起的坑连起来视为一个点,即一块横木板,编上序号,Sample则转化为:

1 0 2 0
0 3 3 3
4 4 4 0
0 0 5 0

需要的板子数为u

再一列一列的操作一次,需要的板子数是v

1 0 4 0
0 3 4 5
2 3 4 0
0 0 4 0

一个坑只能被横着的或者被竖着的木板盖住,将原图的坑的也标上不同的序号,一共九个坑

1 . 2 .
. 3 4 5
6 7 8 .
. . 9 .
 

预处理完之后,所有横向板子即第一个点集,所有竖向板子就是第二个点集,然后再确定边关系,也就是哪些点之间有边,该边就代表了一个洼点,遍历这个图,遇到一个‘*',就说明,其对应的横向板子编号和其对应的竖向板子编号之间存在一条边,然后将对应的点连起来。建完图就二分图最大匹配就行了。可以把这个二分图里的点理解为是板子,然后边理解为是洼地,要求用最少的板子,也就是求最少用最少的点来覆盖所有边。

最后总结一些常用的定理

(1)二分图的最小顶点覆盖 

最小顶点覆盖要求用最少的点(X或Y中都行),让每条边都至少和其中一个点关联。

Knoig定理:二分图的最小顶点覆盖数等于二分图的最大匹配数。

(2)DAG图的最小路径覆盖 

用尽量少的不相交简单路径覆盖有向无环图(DAG)G的所有顶点,这就是DAG图的最小路径覆盖问题。

结论:DAG图的最小路径覆盖数 = 节点数(n)- 最大匹配数(m)

(3)二分图的最大独立集

最大独立集问题: 在N个点的图G中选出m个点,使这m个点两两之间没有边.求m最大值

结论:二分图的最大独立集数 = 节点数(n)— 最大匹配数(m)
 

#include<stdio.h>
#include<iostream>
#include<vector>
#include<string.h>
using namespace std;
int used[2505],r[55][55],c[55][55],nxt[2505];
vector<int>g[2500];
char mp[55][55];
int h,l,u,v;

bool ifind(int x)
{
    int sz=g[x].size();

    for(int i=0;i<sz;i++)
    {

        int p=g[x][i];
        if(!used[p])
        {
            used[p]=1;
            if(nxt[p]==0||ifind(nxt[p]))
            {
                nxt[p]=x;
                return true;
            }
        }
    }
    return false;
}
int match()
{
    int ans=0;
    for(int i=1;i<=u;i++)
    {
        memset(used,0,sizeof(used));
        if(ifind(i))
            ans++;
    }
    return ans;
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin>>h>>l;
    u=0;
    v=0;
    for(int i=0;i<h;i++)
        cin>>mp[i];
    for(int i=0;i<h;i++)
        for(int j=0;j<l;j++)
        {
            if(mp[i][j]=='*')
            {
                u++;
                while(j<l&&mp[i][j]=='*')
                {
                    r[i][j]=u;
                    j++;
                }
            }

        }
    for(int j=0;j<l;j++)
        for(int i=0;i<h;i++)
        {
            if(mp[i][j]=='*')
            {
                v++;
                while(i<h&&mp[i][j]=='*')
                {
                    c[i][j]=v;
                    i++;
                }
            }

        }

    for(int i=0;i<h;i++)
        for(int j=0;j<l;j++)
            if(mp[i][j]=='*')
            {
                g[r[i][j]].push_back(c[i][j]);

            }

    /*cout<<"&************88"<<endl;
    for(int i=1;i<=u;i++)
    {
        int sz=g[i].size();
        cout<<i<<":";
        for(int j=0;j<sz;j++)
            cout<<g[i][j]<<" ";
        cout<<endl;
    }
    cout<<"***********8"<<endl;
    */
    cout<<match()<<endl;
    return 0;







}

猜你喜欢

转载自blog.csdn.net/qq_40642465/article/details/81269361