• 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;
    
    
    
    
    
    
    
    }
  • 相关阅读:
    dotnet OpenXML 解析 PPT 图表 面积图入门
    dotnet 读 WPF 源代码笔记 WPF 是如何做到一套代码兼容多个 .NET Framework 版本
    FileStream 的 FlushAsync 方法在 .NET Framework 与 .NET Core 行为的不同
    dotnet 开启 Fiddler 抓包将会让请求 HOST 头被更改
    查找算法find自定义数据类型
    算数仿函数相加
    查找算法adjacent_find相邻重复元素
    逻辑仿函数非
    关系仿函数大于
    查找算法find_if自定义数据类型
  • 原文地址:https://www.cnblogs.com/eason9906/p/11755041.html
Copyright © 2020-2023  润新知