二分图的最大匹配经典之匈牙利算法

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Doctor的图论计划之——二分图最大匹配

第一讲二分图的最大匹配经典之匈牙利算法

二分图,顾名思义就是分成了两个部分的图……很白痴的解释(自己吐槽了先),但吐槽的同时我们也要发现一些二分图的基本性质!

性质1

二分图之所以分成了两个部分,那是因为单独的一个部分中的任意两点不连通!

性质2

二分图匹配——匈牙利算法中我们只需记录集合1到集合2的单向边就可以了(注意看上边的图,箭头是单向的)思考这是为什么!

但是!二分图确实是无向图!!!只不过匈牙利算法只是从一个集合另一个集合走一遍罢了!!!!

性质3

树是一种特殊的二分图!

紫色的结点构成集合1,绿色的结点构成集合2,换句话说,儿子和爸爸打仗时爷爷和

孙子站在同一战线!(也可以认为是儿子和爸妈吵架时总是爷爷奶奶护着,小时候有这样的记忆没有?反正我没有!)

PS:树就是无回路懂不?

性质3

对于任意二分图,其包含的环一定全部是偶环!(充要可证)

可以证明,含有奇数条边的环一定有两个在相同集合内的点有边相连!

也就是说——二分图的bfs子树一定不含奇环!

接下来说一下二分图求最大匹配的算法——匈牙利算法

【例1】传说中的多米诺骨牌覆盖问题

在一个n*m的棋盘上,摆放一些1*2大小的多米诺骨牌,但棋盘某些地方是坏

掉的,即不能将骨牌置于这些坏掉的格子上,求最多能摆上的骨牌数量

【例2】传说中的猎人打鸟问题

猎人要在n*n的格子里打鸟,他可以在某一行中打一枪,这样此行中的所有鸟都被

打掉,也可以在某一列中打,这样此列中的所有鸟都打掉.问至少打几枪,才能打光

所有的鸟?

【例3】传说中的搞对象问题

一保守教师想带学生郊游, 却怕他们途中谈恋爱,他认为满足下面条件之一的两

人谈恋爱几率很小:

(1)身高差>40 (2) 性别相同(3) 爱好不同类型的音乐(4) 爱好同类型的运动

告诉你每个同学的信息,问老师最多能带多少学生?

这样的问题如何解决?搜索?怎么搜?会不会超时?答案很简单,三道题中的元素都可以用很简单的方式分成两个互不相干的部分,因此可以用二分图匹配来解决这个问题:形象的说,我们规定搞基和百合都是不允许的,已知一群男人和女人,他们可以看做图中的顶点,男人构成了集合A,女人构成了集合B,边表示这名男人和这名女人互相有好感(可以配成一对)不考虑个人因素,现在希望为这些饥渴的男男女女找到最多的配对数(脚踏两只船也是不允许的!)为了解决这样的问题我们才引入了二分图的匹配算法——匈牙利算法!

匈牙利算法是一种用增广路求二分图最大匹配的算法。它由匈牙利数学家Edmonds于1965年提出,因而得名。

如果暴搜的话那么无疑时间复杂度将成为O(2^E)!无法快速实现,于是我们就提出了更为高效的算法,这种算法是从网络流演变而来,但这里我们抛开所有网络流的知识,但从这一算法的角度来进行阐释!

解释一些常用的名词

交错轨:所谓交错轨,还有一种更为文雅的说法叫增广轨,这种说法让人不禁联想到蛋疼的网络流算法,所以我更喜欢用一种与网络流无关的说法来称呼它,下面我们来举几个交错轨的例子:

以上就是一种正确的交错轨,其特点显而易见,黑色表示不连通(虚线找不到就没用)红色表示实线,这样的一虚一实交错的dfs路线称作交错轨

交错轨有以下特点

-交错轨一定是连接AB两个集合,任意两条相邻的边呈相反状态

-交错轨的长度一定为奇数,这是为什么呢?

-交错轨的意义就在于实线联通的两个节点满足“不脚踏两只船”的条件,也就是说被实现连起来的点对满足一种匹配,那么最大匹配也属于一条交错轨!

-将交错轨上的虚实翻转,这样就能使得匹配数+1,这就是为什么交错轨的长度必为奇数!

-还要强调的是,位于交错轨两端的边必须同为虚(这样翻转时才能自增1)

匈牙利算法的实现过程(类似DFS):

1、置已匹配的边集为空

2、由某一集合中的节点X1出发寻找一条交错轨!

3、取反!使得匹配边集变大!

4、继续2过程,对X中的所有元素进行相同操作!

写成伪代码之后就如下:

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的对应项出有可增广路)

匹配数++;

}

输出匹配数;

}

流程图表示!

该算法的复杂度分析:

时间复杂度:邻接矩阵:O(N^3)邻接表:O(N*M)

空间复杂度:邻接矩阵:O(N^2)邻接表:O(N+M)

关于前面例题的点拨:

例1:将棋盘染色,成为国际象棋棋盘一样的颜色,然后将相邻的且两色块都可以放骨牌的顶点用边连起来,可以通过性质证明得到了一张二分图,然后对该二分图求最大匹配!

例2:猎人的目的是打到所有的鸟,言外之意不就是说所有有鸟的方格都要有子弹经过吗?方格是什么?方格不就是由行和列来唯一确定的吗?那么问题是不是就可以转化为用多少颗子弹能把所有的行和列都穿过,如果我们再联想一下,把子弹看作是边,那么问题是不是就变成了最少用多少条边可以把所有的行和列相连,把行看作是一部分点,列看作另一部分点(注意行和列只考虑有鸟的方格)这样,最大匹配数即猎人要打的枪数。

标准代码(pascal):(只贴出匈牙利算法的标程,其余自行脑补!)

Ps:红色部分为关键部分!

const

MXN=1000;

var

g:array[1..MXN,1..MXN] of boolean;

p:array[1..MXN] of longint;

相关文档
最新文档