匈牙利算法
来源:互联网 发布:java泛型的通配符 编辑:程序博客网 时间:2024/06/06 10:39
原文地址:NGUNAUJ的博客
二分图:
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。如下图所示
无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。因此树为二分图。
具体证明参考http://baike.baidu.com/link?url=d2W-kqfBDewABYZs02BEwdrn4EaUzswbKmBTGh782ZKosIIqDhL6PBjAus-uE33Bph-BuZJ51NQtps08pJc0pK
hall 定理 : 对于二分图 G = ( X, Y, E ) , 存在一个匹配M, 使得 X 的所有顶点关于M饱和 的充要条件是: 对 X 的任一子集A , 对A邻接的点集为P (A), 恒有 : | P[A] | >= | A |
匈牙利算法:
给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
v 选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem)
v 如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配。 最大匹配在实际中有广泛的用处,求最大匹配的一种显而易见的算法是:先找出全部匹配,然后保留匹配数最多的。但是这个算法的复杂度为边数的指数级函数。因此,需要寻求一种更加高效的算法。 匈牙利算法是求解最大匹配的有效算法,该算法用到了增广路的定义(也称增广轨或交错轨):若P是图G中一条连通两个未匹配顶点的路径,并且属M的边和不属M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。 由增广路径的定义可以推出下述三个结论:
v 1. P的路径长度必定为奇数,第一条边和最后一条边都不属于M。
v 2. P经过取反操作(即非M中的边变为M中的边,原来M中的边去掉)可以得到一个更大的匹配M’。
v 3. M为G的最大匹配当且仅当不存在相对于M的增广路径。
从而可以得到求解最大匹配的匈牙利算法:
(1)置M为空
(2)找出一条增广路径P,通过取反操作获得更大的匹配M’代替M
(3)重复(2)操作直到找不出增广路径为止 根据该算法,可以用dfs (深度优先搜索)实现。
这里用邻接表存储图伪代码如下:(感谢BYVoid大牛)
bool 寻找从k出发的对应项出的可增广路{ while (从邻接表中列举k能关联到顶点j) { if (j不在增广路上) { 把j加入增广路; if (j是未盖点 或者 从j的对应项出发有可增广路) { 修改j的对应项为k; 则从k的对应项出有可增广路,返回true; } } } 则从k的对应项出没有可增广路,返回false;}void 匈牙利hungary(){ for i->1 to n { if (则从i的对应项出有可增广路) 匹配数++; } 输出 匹配数;}
PS:匈牙利算法在其他方面的应用vector<int>g[maxn];int match[maxn];//存储集合m中的节点i在集合n中的匹配节点,初值为-1bool vis[maxn];int tot,n;bool dfs(int x){for(int i=0;i<g[x].size();i++)if(!vis[g[x][i]]){vis[g[x][i]]=true;if(match[g[x][i]]==-1||dfs(match[g[x][i]])){match[g[x][i]]=x;return true;}}return false;}int hungary(){tot=0;memset(match,-1,sizeof match);for(int i=1;i<=n;i++){memset(vis,0,sizeof vis);if(dfs(i))tot++;}return tot;}
二分图的 最小顶点覆盖 = 最大匹配
DAG图的 最小路径覆盖数 = 节点数 – 最大匹配数
二分图的 最大独立集数 = 节点数 – 最大匹配数
在二分图中求最少的点,让每条边都至少和其中的一个点关联,这就是 二分图的“最小顶点覆盖”。
最小路径覆盖 : 一个PXP的有向图中,路径覆盖就是在图中找一些路经,使之覆 盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联;( 如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以 经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每 每条路径就是一个弱连通子集. 由上面可以得出:
1.一个单独的顶点是一条路径;
2.如果存在一路径p1,p2,……pk,其中p1 为起点,pk为终点,那 么在覆盖图中,顶点p1,p2,……pk不再与其它的顶点之间存在有向边. 最小路径覆盖就是找出最小的路径条数,使之成为P的一个路径覆盖. 路径覆盖与二分图匹配的关系(必须是没有圈的有向图): 最小路径覆盖=|P|-最大匹配数; 其中最大匹配数的求法是把P中的每个顶点pi分成两个顶点pi’与pi”, 如果在p中存在一条pi到pj的边,那么在二分图P'中就有一条连接pi’与 pj”的无向边;这里pi’ 就是p中pi的出边,pj”就是p中pj 的一条入边; 对于公式:最小路径覆盖=|P|-最大匹配数;可以这么来理解; 如果匹配数为零,那么P中不存在有向边,于是显然有: 最小路径覆盖=|P|-最大匹配数=|P|-0=|P|;即P 的最小路径覆盖数为|P|; P'中不在于匹配边时,路径覆盖数为|P|; 如果在P'中增加一条匹配边pi’-->pj”,那么在图P的路径覆盖 中就存在一条由pi连接pj的边,也就是说pi与pj 在一条路径上,于是路 径覆盖数就可以减少一个; 如此继续增加匹配边,每增加一条,路径覆盖数就减少一条;直到 匹配边不能继续增加时,路径覆盖数也不能再减少了,此时就有了前面 的公式;但是这里只 是说明了每条匹配边对应于路径覆盖中的一条路径 上的一条连接两个点之间的有向边;下面来说明一个路径覆盖中的每条 连接两个顶点之间的有向边对应于一条匹配 边; 与前面类似,对于路径覆盖中的每条连接两个顶点之间的每条有向 边pi—>pj,我们可以在匹配图中对应做一条连接pi’与pj”的边, 显然这 样做出来图的是一个匹配图(这一点用反证法很容易证明,如果得到的图 不是一个匹配图,那么这个图中必定存在这样两条边 pi’—pj” 及 pi’ —-pk”, (j!=k),那么在路径覆盖图中就存在了两条边pi–>pj, pi—>pk ,那边从 pi出发的路径就不止一条了,这与路径覆盖图是矛盾的;还有另外一种情况就 是存在pi’—pj”,pk’—pj”,这种情况也类似可证);
至此,就说明了匹配边与路径覆盖图中连接两顶点之间边的一一对应关系, 那么也就说明了前面的公式成立!
PS:http://www.cnblogs.com/jackiesteed/articles/2043934.html
DAG的最小路径覆盖是指找最小数目的互相不相交的有向路径,满足DAG的所有顶点都被覆盖.
首先给出公式:DAG的最小路径覆盖数=DAG图中的节点数-相应二分图中的最大匹配数.
那么对应一个DAG,如何构造相应的二分图?对于DAG中的一个顶点p,二分图中有两个顶点p和p',对应DAG中的一条有向边p->q,二分图中有p-q'的一条无向边.二分图中p属于S集合,p'属于T集合.
下面我们来解释上面公式为什么成立,思路参考baihacker神牛:
那么对应一个DAG,如何构造相应的二分图?对于DAG中的一个顶点p,二分图中有两个顶点p和p',对应DAG中的一条有向边p->q,二分图中有p-q'的一条无向边.二分图中p属于S集合,p'属于T集合.
下面我们来解释上面公式为什么成立,思路参考baihacker神牛:
上图中,对应左边的DAG建立构造右边的二分图,可以找到二分图的一个最大匹配M:1-3',3-4',那么M中的这两条匹配边怎样对应DAG中的路径的边?
使二分图中一条边对应DAG中的一条有向边,1-3'对应DAG图中的有向边1->3,这样DAG中1就会有一个后继顶点(3会是1的唯一后继,因为二分图中一个顶点至多关联一条边!),所以1不会成为DAG中一条路径中的结尾顶点,同样,3-4'对应DAG中3->4,3也不会成为结尾顶点,那么原图中总共4个顶点,减去2个有后继的顶点,就剩下没有后继的顶点,即DAG路径的结尾顶点,而每个结尾顶点正好对应DAG中的一条路径,二分图中寻找最大匹配M,就是找到了对应DAG中的非路径结尾顶点的最大数目,那么DAG中顶点数-|M|就是DAG中结尾顶点的最小数目,即DAG的最小路径覆盖数.
0 0
- 匈牙利算法
- 匈牙利算法!!!
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 10分钟学会理解和解决MySQL乱码问题
- iText操作PDF学习(一)
- Unity 添加天空盒的两种方法
- PCI总线(国嵌笔记)
- hibernate主键生成策略
- 匈牙利算法
- boost::asio译文
- html document.getElement(s)By..
- Android 组件间的解耦
- 蓝桥杯 - 兰顿蚂蚁 (模拟)
- DMA的外设地址简单说明
- Android 百度地图 SDK v3.0.0 (四) 引入离线地图功能
- 【问题】html列表项,内容随着鼠标移动而变化的页面,怎样实现?
- PCI驱动程序(国嵌笔记)