zoukankan      html  css  js  c++  java
  • 最大匹配、最小顶点覆盖、最大独立集、最小路径覆盖(转)

    在讲述这两个算法之前,首先有几个概念需要明白:

    二分图: 
    二分图又称二部图,是图论中的一种特殊模型。设G=(V,E)是一个无向图,如果顶点V可以分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A, j in B), 则称图G是二分图。 


    匹配: 
    给定一个二分图,在G的一个子图G’中,如果G’的边集中的任意两条边都不依附于同一个顶点,则称G’的边集为G的一个匹配 

    最大匹配: 
    在所有的匹配中,边数最多的那个匹配就是二分图的最大匹配了 

    顶点覆盖: 
    在顶点集合中,选取一部分顶点,这些顶点能够把所有的边都覆盖了。这些点就是顶点覆盖集

    最小顶点覆盖: 
    在所有的顶点覆盖集中,顶点数最小的那个叫最小顶点集合。 

    独立集: 
    在所有的顶点中选取一些顶点,这些顶点两两之间没有连线,这些点就叫独立集 

    最大独立集: 
    在左右的独立集中,顶点数最多的那个集合 

    路径覆盖: 
    在图中找一些路径,这些路径覆盖图中所有的顶点,每个顶点都只与一条路径相关联。 

    最小路径覆盖: 
    在所有的路径覆盖中,路径个数最小的就是最小路径覆盖了。 
    熟悉了这些概念之后,还有一个二分图最大匹配的König定理,这个定理的内容是:最大匹配 = 最小顶点覆盖。此处不证明其正确性。有了这个定理之后还可以得出一些二分图特有的公式: 

    最大独立集 = 顶点个数 – 最小顶点覆盖(最大匹配) 
    这个公式,我们可以利用最大匹配来找到最大的独立集。而最大独立集和最小路径覆盖有个千丝万缕的关系。 
    对于二分图的最大匹配,常用的求解方法是hungarian算法和最大流算法。以poj上的题目为例说明: 
    POJ2271: 题目大意是,一群男孩和女孩共N人,某些男孩和女孩之间会发生恋爱关系(满足一定的关系),现在希望找到最多的孩子,他们之间不会发生恋爱关系。 
    分析:找到最多的孩子,没有恋爱关系,这实质上是找最大独立集。假设男孩在左有a个,女孩在右有b个,那么如果某男孩和某女孩之间有关系,就连线。最大独立集就是找到最多顶点,顶点之间没有联系,正好就是所求,而最大独立集就是 N-最大匹配,所以问题得到解决。试想,如果二分图中没有连线,那么所有的孩子都可选,最大独立集也是N,他们是等价的。如果存在一条连线,那么去掉一个孩子就是所找的孩子,最大独立集此时是N-1.依次类推。在试想,最大匹配其实就找到了几对恋爱对象,假设是这样的 
    a b 
    B0 G0 
    B1 G1 
    … … 
    Bi Gi 
    … … 
    我们只需要把他们的另一半去掉,就是我们找的孩子。不过会有这样的疑问,如果我取出了B1的另一半G1,B1会不会和其余的孩子恋爱呢,比如说B1和b会恋爱,那么好吧,去掉G1的另一半B1,这样就不会有问题了吧。还有担心?G1会不会和其余的孩子恋爱呢,比如说G1和a会恋爱,不过这样的情况是不会出现的。假如G1和a好,B1和b好,那么最大匹配中出现的是两条边G1->a B1->b,而不是现在的B1和G1.所以,既然最大匹配中选择了B1和G1,去掉他们中间的一个肯定是可行的。所以答案就是N-最大匹配了。 


    POJ3692:题目大意是,一群男孩B个(他们互相认识),一群女孩G个(他们互相认识),某些男孩和某些女孩相识,现在找出最多的孩子,他们互相认识 
    分析:这个题目和上面的有些相似。对于利用二分图最大匹配算法解题最重要不是匹配算法本身,而是如何问题转化为二分图模型。一旦模型建立,就很容易了。题目要找的是一群孩子,他们之间都互相认识,也就是说这是一个团(图的概念,任意两个顶点之间都有连线)。可是如果直接去找团,可能比较麻烦。因为这是二分图,自然要利用二分图的性质。在二分图的算法里面没有找团的相关算法,所以我们可以考虑反问题,找出最多的孩子,他们之间互不认识,这不是就是求最大独立集嘛。建立这样的二分图,左边是男孩,右边是女孩,如果男孩和女孩不认识就连上边,在这样的二分图中,找最大独立集,其实就是找出所有的相互认识的孩子了。接下来就很容易了。此题说明模型的转化和构图很重要。 


    POJ3041:题目大意是,一个矩阵,某些位置有小行星,有一种炸弹,一次可以炸掉一行或者一列,现在问题是需要最少用多少这样的炸弹。 
    分析:模型转化,非常巧妙的利用二分图来解决。利用二分图必须有左顶点和右顶点,我们把行作为左顶点,列作为右顶点,如果该行和该列的交点有小行星,就连线。求此二分图的最大匹配就是了。对这个问题展开思考,为什么可以这么转化。其实从最小顶点覆盖的角度来想比较好理解,左边的顶点和右边的顶点只有当有小行星的时候才有连线,那么只要找到最少的顶点把所有的边覆盖了,那么就是所求的解了。最小顶点覆盖等值于最大匹配 


    POJ1466:题目大意是,一群人N,某人可能是多某些人有罗曼史,性别未知,但一定是异性。找出最多的同学,他们之间无罗曼史 
    分析:因为性别未知,所以可以把所有的人当成左顶点,右边也是所有的人,建立二分图,可以想象,这样求出来的最大匹配是男女分开建立的二分图的最大匹配的二倍。而题目让找最大独立集,所以应该是N-最大匹配/2; 


    POJ1325:题目大意是,有两台机器,有多个任务,每个任务都可在这两台机器上运行,不过不同的模式需要重启电脑,很浪费时间,现在要找出最好的调度方式,减少调度时间。 
    分析:最少的顶点覆盖最多的边(任务),所以是最小顶点覆盖问题 


    POJ2060:题目大意,有很多人预订出租车,如果出租车做完一个任务能够敢到下一个任务,就不需要在调度一辆出租车了,现在请问最少需要几辆出租车。 
    分析:最小路径问题,对任务构图,将一个任务拆开成两个点,建立二分图,如果一个任务能够完成之后赶到下个任务就连线,然后就是二分图问题了。最小路径等值于二分图的最大独立集 


    POJ2226:和3041相似,不过这里不是销毁一行或者一列,一次只能销毁连着的一行或者一列。可以把所有的行连续的段拿出来作为左顶点,所有的列连续的段拿出来作为右顶点,如果左段与右段之间有相交,就连线。然后求最小顶点覆盖 
    POJ1422:最小路径覆盖 
    POJ2594:特殊的最小路径覆盖,每个顶点可以有多条路径经过,这时需要事先把任意两点之间是否能够到达求出,然后在求路径覆盖。 
    POJ1548:最小路径覆盖 
    POJ3216:最小路径覆盖

     

    二分图最小顶点覆盖的证明 
    首先,回顾一下二分图最小点覆盖的定义: 
    二分图中,选取最少的点数,使这些点和所有的边都有关联(把所有的边的覆盖),叫做最小点覆盖。 
    最少点数=最大匹配数 
    结合昨天看的介绍,,今天按照我的理解给出自己的证明(原创,仅作参考,欢迎讨论) 
    从最大匹配数到底能不能覆盖所有的边入手。 
    因为已知了最大匹配,所有再也不能找到增广路了,有最大匹配定义知。 
    现在所有的边就剩下两种情况了,一种是匹配,一种是不匹配。 
    假设所有的匹配边有n条,那么左右边就都有n个匹配边的顶点了,标记所有左边匹配边的顶点,则有n个。 
    问题就是证明n=最小点覆盖,即证明最大匹配数n到底能不能覆盖所有的边入手。 
    考察右边的匹配边的顶点,明显,左边都可以找到其匹配点且为n,说明所有匹配边已经被这左边的n个点关联了。 
    接下来证明未匹配边也能被这左边的n个匹配的点关联那么不就证明了“,使这些点和所有的边都有关联(把所有的边的覆盖)”吗。。 
    对于剩下的未匹配边,每条边都有一个右边点(显然既然是未匹配边,这个点自然是未匹配点)和左边点(我将证明着些左边点都是匹配边的顶点,证明了这一点,也就证明了这左边的n个点也和剩下的未匹配边关联了) 
    假设上面说的左边点不在这n个匹配边的左边点之中,那从剩下的某个未匹配边的右边点出发不就可以找到增广路了吗(想想增广路的定义就知道了,右未匹配,左未匹配的话那就可以找到增广路了),所以左边点也在匹配边之中,。所以就证明了剩下的未匹配边关联的范围也在这左边的n个匹配点的范围内力了。 
    也就证明了这n个左边匹配边的点既也右边匹配边关联,也与右边未匹配边关联了,即与所有边关联了。 
    那么按照最小覆盖的定义,接下来只要证明这个n是做小值就行了。 
    假设可以比n小,那就相当于随便删一些匹配边,那么这些删除了边的右边点就没人匹配了,也就不满足与所以边关联了,所以矛盾,所有n就是最小值。 
    故得证。 
    主要从最小覆盖的定义的两个要点(1,能不能关联所有的边。2,最小)来证明最大匹配的所有左边点就满足这个要求,匹配边有n条那自然匹配边的左边点就有n个了。

    转载自:http://blog.sina.com.cn/s/blog_5ceeb9ea0100l08n.html

     

    性质: 
    最大团 = 补图的最大独立集

    最小边覆盖 = 二分图最大独立集 = |V| - 最小路径覆盖

    最小路径覆盖 = |V| - 最大匹配数

    最小顶点覆盖 = 最大匹配数

    最小顶点覆盖 + 最大独立数 = |V|

    最小割 = 最小点权覆盖集 = 点权和 - 最大点权独立集

     

     

    不错的讲解二分图大讲堂http://dsqiu.iteye.com/blog/1689505

  • 相关阅读:
    【Anagrams】 cpp
    【Count and Say】cpp
    【Roman To Integer】cpp
    【Integer To Roman】cpp
    【Valid Number】cpp
    重构之 实体与引用 逻辑实体 逻辑存在的形式 可引用逻辑实体 不可引用逻辑实体 散弹式修改
    Maven项目聚合 jar包锁定 依赖传递 私服
    Oracle学习2 视图 索引 sql编程 游标 存储过程 存储函数 触发器
    mysql案例~tcpdump的使用
    tidb架构~本地化安装
  • 原文地址:https://www.cnblogs.com/wd-one/p/4547616.html
Copyright © 2011-2022 走看看