【算法设计与数据结构】匈牙利算法求最大匹配

来源:互联网 发布:udp端口在线扫描 编辑:程序博客网 时间:2024/05/17 23:57

简介

设G=(V,E)是一个无向图。如顶点集V可分割为两个互不相交的子集V1,V2,选择这样的子集中边数最大的子集称为图的最大匹配问题(maximal matching problem)

如果一个匹配中,|V1|<=|V2|且匹配数|M|=|V1|则称此匹配为完全匹配,也称作完备匹配。特别的当|V1|=|V2|称为完美匹配。

简易入门教程

趣写算法系列之–匈牙利算法
http://blog.csdn.net/dark_scope/article/details/8880547

相关概念

图G

M是G的一个匹配。
(M:{(x2,y4),(x3,y1),(x4,y3),(x6,y5)})

M-交错路:p是G的一条通路,如果p中的边为属于M中的边与不属于M但属于G中的边交替出现,则称p是一条M-交错路。例如:x1-y1-x3-y2

M-饱和点:对于v∈V(G),如果v与M中的某条边关联,则称v是M-饱和点,否则称v是非M-饱和点。如x2,x3,x4,x6,y1,y3,y4,y5都属于M-饱和点,而其它点都属于非M-饱和点。

M-可增广路:p是一条M-交错路,如果p的起点和终点都是非M-饱和点,则称p为M-可增广路。例如:x1-y1-x3-y2

求最大匹配的一种显而易见的算法是:先找出全部匹配,然后保留匹配数最多的。但是这个算法的时间复杂度为边数的指数级函数。因此,需要寻求一种更加高效的算法。下面介绍用增广路求最大匹配的方法(称作匈牙利算法,匈牙利数学家Edmonds于1965年提出)。

由增广路的定义可以推出下述三个结论:    1-P的路径个数必定为奇数,第一条边和最后一条边都不属于M。    2-将M和P进行取反操作可以得到一个更大的匹配M'。    3-M为G的最大匹配当且仅当不存在M的增广路径。

算法轮廓

    ⑴置M为空    ⑵找出一条增广路径P,通过异或操作获得更大的匹配M'代替M    ⑶重复⑵操作直到找不出增广路径为止

在这个过程中,如何快速找出增广路呢?

这里提供一种方法:如下图所示,找一个非M-饱和点,画一棵M-交错树,如果能找到,就重复(2),不能找到算法就可以结束咯~

M-交错树

代码

//伪代码bool 寻找从k出发的增广路{    for (k的所有邻接点j)    {        if (j不在增广路上)        {            把j加入增广路;            if (j是非-M饱和点 或者 从j的对应项出发有可增广路)            {                修改j的对应项为k;                返回true;            }        }    }    返回false;}void 匈牙利hungary(){    for i->1 to n    {        if (则从i出发有增广路)            匹配数++;    }    输出 匹配数;}
//C++代码//b[j]表示j的匹配对象,0表示未匹配bool find(int x){    for (int j = 1;j <= n;j++)    {           if (arc[x][j]&& !v[j])        {            v[j]=1;            if (b[j]==0 || find(b[j]))             {                 b[j] = x;                return true;            }        }    }    return false;}for (int i = 1; i <= m; i++){    memset(v,0,sizeof(v)); //注意每一次v都要清空,每一次找增广路都是一次新的开始    if (find(i)) ans += 1;}

对递归的一些理解

图G

如图G,比如我们现在进行find(x1);
x1会去找y1,但是发现b[y1]不是0了,于是递归进行find(x3),此时v[y1]=1,已经被标记,所以x3不能再找y1了,于是它找到了y2(当然,如果y2已经名花有主,那么再次递归,让y2的主另寻他欢)

在这个过程中,发生了这样的事情:我们试图将(x1, y1),(x3, y2)增加到M中,而将(x3,y1)从M中删除——这正是在试图用M’来代替M,一旦找到增广路,返回true,则递归收缩回来,逐步执行b[j]=x来修改边,如果找不到增广路,返回false,则一切的修改都不会执行。

0 0
原创粉丝点击