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

简介

设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,则一切的修改都不会执行。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值