用匈牙利算法求二分图的最大匹配
最佳重分配 匈牙利算法

最佳重分配匈牙利算法最佳重分配匈牙利算法,也叫作匈牙利算法,是一种常用于解决二分图最大匹配问题的算法。
本文将介绍最佳重分配匈牙利算法的定义、原理、实现和应用。
一、算法定义最佳重分配匈牙利算法是一种寻找二分图最大匹配的算法,其基本思想是在尽可能增大匹配的前提下,找到每个左部点的最优匹配。
此算法能够有效应对利用贪心或DFS算法求得的最大匹配值较小的情况。
二、算法原理最佳重分配匈牙利算法是一个基于DFS搜索的寻找最大匹配的算法。
它的基本思路是从左边开始枚举每一个左部点,在右边的匹配点中找到最合适的点。
若最后所有的左部点都能找到匹配的右部点,则此时为最大匹配。
而如果出现找不到匹配点的情况,就需要对已经匹配的边进行重分配。
同时,算法也支持权重匹配,即将边的权重加入到选取匹配点的决策中,从而更准确地匹配。
三、算法实现最佳重分配匈牙利算法实现过程主要由以下几个步骤组成:1.从左边第一个点开始,寻找与其最优匹配的右部点,就是尝试将这个左部点与右部图的所有未被匹配过的点进行匹配,其中匹配的条件是要满足没有与其他左部点有相同的匹配。
2.如果找到一个匹配的右部点,那么将这个左部点和右部点建立匹配关系,并将右部点状态设置为已匹配。
3.如果没有找到合适的右部点,就要进行匹配重分配。
首先,将已经进行了匹配而且在重分配环中的所有点按照交替方式重新相连,形成一个环-链数据结构;同时,计算出这个环-链中权重最小的边的权重,然后将环-链上的奇数边权的点减去该最小值,偶数边的点加上该最小值。
最后,通过交替路径来更新匹配。
4.根据已经匹配的点的数量,决定是否需要继续匹配,若所有的左部点都找到了匹配的右部点,则证明达到了最大匹配。
四、算法应用最佳重分配匈牙利算法在实际应用中有着广泛的应用场景,主要用于解决二分图最大匹配问题。
例如在对学生和导师之间进行匹配、对工人和工作之间进行匹配时,就可以使用该算法来解决问题。
总体来说,最佳重分配匈牙利算法具有高效、简洁、易于实现和适用于多种场景的优点。
匈牙利算法解决二分图最大匹配

匈⽛利算法解决⼆分图最⼤匹配预备知识 匈⽛利算法是由匈⽛利数学家Edmonds于1965年提出,因⽽得名。
匈⽛利算法是基于Hall定理中充分性证明的思想,它是⼆分图匹配最常见的算法,该算法的核⼼就是寻找增⼴路径,它是⼀种⽤增⼴路径求⼆分图最⼤匹配的算法。
⼆分图 ⼆分图⼜称作⼆部图,是图论中的⼀种特殊模型。
设G=(V,E)是⼀个⽆向图,如果顶点V可分割为两个互不相交的⼦集(A,B),并且图中的每条边(i,j)所关联的两个顶点 i 和 j 分别属于这两个不同的顶点集(i in A,j in B),则称图G为⼀个⼆分图。
匹配 在图论中,⼀个图是⼀个匹配(或称独⽴边集)是指这个图之中,任意两条边都没有公共的顶点。
这时每个顶点都⾄多连出⼀条边,⽽每⼀条边都将⼀对顶点相匹配。
例如,图3、图4中红⾊的边就是图2的匹配。
图3中1、4、5、7为匹配点,其他顶点为⾮匹配点,1-5、4-7为匹配边,其他边为⾮匹配边。
最⼤匹配 ⼀个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最⼤匹配。
图 4 是⼀个最⼤匹配,它包含 4 条匹配边。
任意图中,极⼤匹配的边数不少于最⼤匹配的边数的⼀半。
完美匹配 如果⼀个图的某个匹配中,所有的顶点都是匹配点,那么它就是⼀个完美匹配。
显然,完美匹配⼀定是最⼤匹配,但并⾮每个图都存在完美匹配。
最⼤匹配数:最⼤匹配的匹配边的数⽬。
最⼩点覆盖数:选取最少的点,使任意⼀条边⾄少有⼀个端点被选择。
最⼤独⽴数:选取最多的点,使任意所选两点均不相连。
最⼩路径覆盖数:对于⼀个DAG(有向⽆环图),选取最少条路径,使得每个顶点属于且仅属于⼀条路径,路径长可以为0(即单个点)定理1:Konig定理——最⼤匹配数 = 最⼩点覆盖数定理2:最⼤匹配数 = 最⼤独⽴数定理3:最⼩路径覆盖数 = 顶点数 - 最⼤匹配数匈⽛利算法例⼦ 为了便于理解,选取了dalao博客⾥找妹⼦的例⼦: 通过数代⼈的努⼒,你终于赶上了剩男剩⼥的⼤潮,假设你是⼀位光荣的新世纪媒⼈,在你的⼿上有N个剩男,M个剩⼥,每个⼈都可能对多名异性有好感(惊讶,-_-||暂时不考虑特殊的性取向) 如果⼀对男⼥互有好感,那么你就可以把这⼀对撮合在⼀起,现在让我们⽆视掉所有的单相思(好忧伤的感觉,快哭了),你拥有的⼤概就是下⾯这样⼀张关系图,每⼀条连线都表⽰互有好感。
匈牙利算法基于的原理

匈牙利算法基于的原理匈牙利算法是一种解决二分图最大匹配的算法。
所谓二分图,是指一个图的顶点集可以分为两个互不相交的子集U、V,并且图中的每条边的一个端点属于U,另一个端点属于V。
最大匹配是指在二分图中找到一个由最多边组成的子图,使得任意两条边都没有共同的顶点。
首先,将所有的顶点标记为未匹配状态。
然后,从未匹配顶点开始,逐步增加匹配边。
在增加匹配边的过程中,如果可以找到增广路径,就将这条路径上的匹配边翻转,从而增加匹配数目。
重复这个过程,直到没有增广路径可找到为止。
具体步骤如下:1.选取一个未匹配顶点u,将其标记为已匹配状态。
2.对于u的每个邻居节点v,如果v是未匹配的,或者可以通过v的已匹配节点找到更长的增广路径,那么将v标记为已匹配状态,并将u与v匹配。
3.如果v已经是已匹配的,但是可以通过v的已匹配节点找到更长的增广路径,那么将u与v匹配,同时将原来与v匹配的节点转变为未匹配状态,并将u标记为已匹配状态。
4.重复上述步骤,直到所有节点均被匹配。
匈牙利算法的核心在于寻找增广路径的过程。
为了避免重复增广路径,一种常用的方法是采用深度优先。
通过深度优先,可以找到从未匹配节点u到已匹配节点v的一条最长增广路径。
在深度优先的过程中,需要借助一个辅助数组match[]来记录节点的匹配状态。
总结起来,匈牙利算法基于深度优先和增广路径的概念来寻找二分图的最大匹配。
其原理是通过逐步增加匹配边,找到增广路径来增加匹配数目。
通过标记节点的匹配状态,并通过深度优先来寻找增广路径,从而得到最大匹配。
二分图匹配(匈牙利算法)

设G=(V,{R})是一个无向图。
如顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属两个不同的子集。
则称图G为二分图。
v给定一个二分图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的增广路径。
从而可以得到求解最大匹配的匈牙利算法:v(1)置M为空v(2)找出一条增广路径P,通过取反操作获得更大的匹配M’代替Mv(3)重复(2)操作直到找不出增广路径为止根据该算法,我选用dfs (深度优先搜索)实现。
程序清单如下:int match[i] //存储集合m中的节点i在集合n中的匹配节点,初值为-1。
int n,m,match[100]; //二分图的两个集合分别含有n和m个元素。
bool visit[100],map[100][100]; //map存储邻接矩阵。
bool dfs(int k){int t;for(int i = 0; i < m; i++)if(map[k][i] && !visit[i]){visit[i] = true;t = match[i];match[i] = k; //路径取反操作。
python实现匈牙利算法求解二分图最大匹配

python实现匈⽛利算法求解⼆分图最⼤匹配重点:理解和取反1. 匈⽛利算法求解⽬标:找到⼆分图的最⼤匹配整体思路:每⼀步寻找⼀条增⼴路径,取反2. 关键步骤⼆分图的顶点分为左边点集X和右边点集Y,假定遍历的点集是X。
对于每⼀次迭代的点x_i,1. 搜索增⼴路径:遍历x_i的邻接节点y_j1. 如果y_j未匹配,则找到增⼴路2. 如果y_j已匹配,则寻找y_j的匹配节点的增⼴路径(深搜或者⼴搜)2. 取反:把增⼴路径中的已经匹配边改成未匹配;未匹配的改成匹配3. python代码算法输⼊为字典形式的特殊邻接表。
特殊之处在于字典的键和值的顶点分别属于⼆分图的左右点集合。
深度搜索增⼴路径函数的参数中的visited_set的作⽤是避免重复访问。
# 匈⽛利算法(dfs)class Hungarian:def search_extend_path(self, l_node, adjoin_map, l_match, r_match, visited_set):'''深度搜索增⼴路径'''for r_node in adjoin_map[l_node]: # 邻接节点if r_node not in r_match.keys(): # 情况1:未匹配, 则找到增⼴路径,取反l_match[l_node] = r_noder_match[r_node] = l_nodereturn Trueelse: # 情况2: 已匹配next_l_node = r_match[r_node]if next_l_node not in visited_set:visited_set.add(next_l_node)if self.search_extend_path(next_l_node, adjoin_map, l_match, r_match, visited_set): # 找到增⼴路径,取反l_match[l_node] = r_noder_match[r_node] = l_nodereturn Truereturn Falsedef run(self, adjoin_map):''':param adjoin_map: {x_i: [y_j, y_k]}:return:'''l_match, r_match = {}, {} # 存放匹配for lNode in adjoin_map.keys():self.search_extend_path(lNode, adjoin_map, l_match, r_match, set())return l_match。
最大二分图匹配(匈牙利算法)

最大二分图匹配(匈牙利算法)二分图指的是这样一种图:其所有的顶点分成两个集合M和N,其中M或N中任意两个在同一集合中的点都不相连。
二分图匹配是指求出一组边,其中的顶点分别在两个集合中,并且任意两条边都没有相同的顶点,这组边叫做二分图的匹配,而所能得到的最大的边的个数,叫做最大匹配。
计算二分图的算法有网络流算法和匈牙利算法(目前就知道这两种),其中匈牙利算法是比较巧妙的,具体过程如下(转自组合数学):令g=(x,*,y)是一个二分图,其中x={x1,x2...},y={y1,y2,....}.令m为g中的任意匹配。
1。
将x的所有不与m的边关联的顶点表上¥,并称所有的顶点为未扫描的。
转到2。
2。
如果在上一步没有新的标记加到x的顶点上,则停,否则,转33。
当存在x被标记但未被扫描的顶点时,选择一个被标记但未被扫描的x的顶点,比如xi,用(xi)标记y 的所有顶点,这些顶点被不属于m且尚未标记的边连到xi。
现在顶点xi 是被扫描的。
如果不存在被标记但未被扫描的顶点,转4。
4。
如果在步骤3没有新的标记被标记到y的顶点上,则停,否则转5。
5。
当存在y被标记但未被扫描的顶点时。
选择y的一个被标记但未被扫描的顶点,比如yj,用(yj)标记x的顶点,这些顶点被属于m且尚未标记的边连到yj。
现在,顶点yj是被扫描的。
如果不存在被标记但未被扫描的顶点则转道2。
由于每一个顶点最多被标记一次且由于每一个顶点最多被扫描一次,本匹配算法在有限步内终止。
代码实现:bfs过程:#include<stdio.h>#include<string.h>main(){bool map[100][300];inti,i1,i2,num,num1,que[300],cou,stu,match1[100],match2[300],pqu e,p1,now,prev[300],n;scanf("%d",&n);for(i=0;i<n;i++){scanf("%d%d",&cou,&stu);memset(map,0,sizeof(map));for(i1=0;i1<cou;i1++){scanf("%d",&num);for(i2=0;i2<num;i2++){scanf("%d",&num1);map[i1][num1-1]=true;}}num=0;memset(match1,int(-1),sizeof(match1)); memset(match2,int(-1),sizeof(match2)); for(i1=0;i1<cou;i1++){p1=0;pque=0;for(i2=0;i2<stu;i2++){if(map[i1][i2]){prev[i2]=-1;que[pque++]=i2;}elseprev[i2]=-2;}while(p1<pque){now=que[p1];if(match2[now]==-1)break;p1++;for(i2=0;i2<stu;i2++){if(prev[i2]==-2&&map[match2[now]][i2]){prev[i2]=now;que[pque++]=i2;}}}if(p1==pque)continue;while(prev[now]>=0){match1[match2[prev[now]]]=now; match2[now]=match2[prev[now]]; now=prev[now];}match2[now]=i1;match1[i1]=now;num++;}if(num==cou)printf("YES\n");elseprintf("NO\n");}}dfs实现过程:#include<stdio.h>#include<string.h>#define MAX 100bool map[MAX][MAX],searched[MAX]; int prev[MAX],m,n;bool dfs(int data){int i,temp;for(i=0;i<m;i++){if(map[data][i]&&!searched[i]){searched[i]=true;temp=prev[i];prev[i]=data;if(temp==-1||dfs(temp))return true;prev[i]=temp;}}return false;}main(){int num,i,k,temp1,temp2,job;while(scanf("%d",&n)!=EOF&&n!=0) {scanf("%d%d",&m,&k);memset(map,0,sizeof(map));memset(prev,int(-1),sizeof(prev)); memset(searched,0,sizeof(searched));for(i=0;i<k;i++){scanf("%d%d%d",&job,&temp1,&temp2); if(temp1!=0&&temp2!=0)map[temp1][temp2]=true;}num=0;for(i=0;i<n;i++){memset(searched,0,sizeof(searched)); dfs(i);}for(i=0;i<m;i++){if(prev[i]!=-1)num++;}printf("%d\n",num);}}。
数学建模匈牙利算法

数学建模匈牙利算法
【最新版】
目录
一、匈牙利算法的概念与基本原理
二、匈牙利算法的应用实例
三、匈牙利算法的优缺点
正文
一、匈牙利算法的概念与基本原理
匈牙利算法(Hungarian algorithm)是一种求解二分图最大匹配问题的算法,由匈牙利数学家 Mátyásovszky 于 1937 年首次提出。
该算法的基本思想是:通过不断循环寻找图中的偶数长度路径,并将路径中的顶点依次匹配,直到找不到这样的路径为止。
此时,图中的所有顶点都已匹配,即得到了二分图的最大匹配。
二、匈牙利算法的应用实例
匈牙利算法广泛应用于任务分配、资源调度、数据融合等领域。
下面举一个简单的例子来说明匈牙利算法的应用。
假设有 5 个工人和 8 个任务,每个工人完成不同任务的效率不同。
我们需要为每个任务分配一个工人,使得总效率最大。
可以用一个二分图来表示这个问题,其中顶点分为两类:工人和任务。
边表示任务与工人之间的效率关系。
匈牙利算法可以用来求解这个问题,找到最优的任务分配方案。
三、匈牙利算法的优缺点
匈牙利算法的优点是简单、高效,可以解决二分图的最大匹配问题。
然而,它也存在一些缺点:
1.匈牙利算法只能解决无向图的匹配问题,对于有向图,需要将其转
换为无向图才能使用匈牙利算法。
2.当图中存在环时,匈牙利算法无法找到最大匹配。
这时需要使用其他算法,如 Euclidean algorithm(欧几里得算法)来解决。
3.匈牙利算法在实际应用中可能存在数值稳定性问题,即在计算过程中可能出现精度误差。
二分图最大匹配总结

⼆分图最⼤匹配总结⼆分图匹配(匈⽛利算法)1。
⼀个⼆分图中的最⼤匹配数等于这个图中的最⼩点覆盖数König定理是⼀个⼆分图中很重要的定理,它的意思是,⼀个⼆分图中的最⼤匹配数等于这个图中的最⼩点覆盖数。
如果你还不知道什么是最⼩点覆盖,我也在这⾥说⼀下:假如选了⼀个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖所有的边。
2。
最⼩路径覆盖=最⼩路径覆盖=|G|-最⼤匹配数在⼀个N*N的有向图中,路径覆盖就是在图中找⼀些路经,使之覆盖了图中的所有顶点,且任何⼀个顶点有且只有⼀条路径与之关联;(如果把这些路径中的每条路径从它的起始点⾛到它的终点,那么恰好可以经过图中的每个顶点⼀次且仅⼀次);如果不考虑图中存在回路,那么每每条路径就是⼀个弱连通⼦集.由上⾯可以得出:1.⼀个单独的顶点是⼀条路径;2.如果存在⼀路径p1,p2,......pk,其中p1 为起点,pk为终点,那么在覆盖图中,顶点p1,p2,......pk不再与其它的顶点之间存在有向边.最⼩路径覆盖就是找出最⼩的路径条数,使之成为G的⼀个路径覆盖.路径覆盖与⼆分图匹配的关系:最⼩路径覆盖=|G|-最⼤匹配数;3。
⼆分图最⼤独⽴集=顶点数-⼆分图最⼤匹配独⽴集:图中任意两个顶点都不相连的顶点集合。
⼆分图模板:模板⼀:匈⽛利算法/* **************************************************************************//⼆分图匹配(匈⽛利算法的DFS实现)//初始化:g[][]两边顶点的划分情况//建⽴g[i][j]表⽰i->j的有向边就可以了,是左边向右边的匹配//g没有边相连则初始化为0//uN是匹配左边的顶点数,vN是匹配右边的顶点数//调⽤:res=hungary();输出最⼤匹配数//优点:适⽤于稠密图,DFS找增⼴路,实现简洁易于理解//时间复杂度:O(VE)//***************************************************************************///顶点编号从0开始的const int MAXN=510;int uN,vN;//u,v数⽬int g[MAXN][MAXN];int linker[MAXN];bool used[MAXN];bool dfs(int u)//从左边开始找增⼴路径{int v;for(v=0;v<vN;v++)//这个顶点编号从0开始,若要从1开始需要修改if(g[u][v]&&!used[v]){used[v]=true;if(linker[v]==-1||dfs(linker[v])){//找增⼴路,反向linker[v]=u;return true;}}return false;//这个不要忘了,经常忘记这句}int hungary(){int res=0;int u;memset(linker,-1,sizeof(linker));for(u=0;u<uN;u++){memset(used,0,sizeof(used));if(dfs(u)) res++;}return res;}//******************************************************************************/模板⼆: Hopcroft-Carp算法这个算法⽐匈⽛利算法的时间复杂度要⼩,⼤数据可以采⽤这个算法/* *********************************************⼆分图匹配(Hopcroft-Carp的算法)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
用匈牙利算法求二分图的最大匹配
什么是二分图,什么是二分图的最大匹配,这些定义我就不讲了,网上随便都找得到。
二分图的最大匹配有两种求法,第一种是最大流(我在此假设读者已有网络流的知识);第二种就是我现在要讲的匈牙利算法。
这个算法说白了就是最大流的算法,但是它跟据二分图匹配这个问题的特点,把最大流算法做了简化,提高了效率。
匈牙利算法其实很简单,但是网上搜不到什么说得清楚的文章。
所以我决定要写一下。
最大流算法的核心问题就是找增广路径(augment path)。
匈牙利算法也不例外,它的基本模式就是:
初始时最大匹配为空
while 找得到增广路径
do 把增广路径加入到最大匹配中去
可见和最大流算法是一样的。
但是这里的增广路径就有它一定的特殊性,下面我来分析一下。
(注:匈牙利算法虽然根本上是最大流算法,但是它不需要建网络模型,所以图中不再需要源点和汇点,仅仅是一个二分图。
每条边也不需要有方向。
)
图1是我给出的二分图中的一个匹配:[1,5]和[2,6]。
图2就是在这个匹配的基础上找到的一条增广路径:3->6->2->5->1->4。
我们借由它来描述一下二分图中的增广路径的性质:
(1)有奇数条边。
(2)起点在二分图的左半边,终点在右半边。
(3)路径上的点一定是一个在左半边,一个在右半边,交替出现。
(其实二分图的性质就决定了这一点,因为二分图同一边的点之间没有边相连,不要忘记哦。
)
(4)整条路径上没有重复的点。
(5)起点和终点都是目前还没有配对的点,而其它所有点都是已经配好对的。
(如图1、图2所示,[1,5]和[2,6]在图1中是两对已经配好对的点;而起点3和终点4目前还没有与其它点配对。
)
(6)路径上的所有第奇数条边都不在原匹配中,所有第偶数条边都出现在原匹配中。
(如图1、图2所示,原有的匹配是[1,5]和[2,6],这两条配匹的边在图2给出的增广路径中分边是第2和第4条边。
而增广路径的第1、3、5条边都没有出现在图1给出的匹配中。
)
(7)最后,也是最重要的一条,把增广路径上的所有第奇数条边加入到原匹配中
去,并把增广路径中的所有第偶数条边从原匹配中删除(这个操作称为增广路径的取反),则新的匹配数就比原匹配数增加了1个。
(如图2所示,新的匹配就是所有蓝色的边,而所有红色的边则从原匹配中删除。
则新的匹配数为3。
)
不难想通,在最初始时,还没有任何匹配时,图1中的两条灰色的边本身也是增广路径。
因此在这张二分图中寻找最大配匹的过程可能如下:
(1)找到增广路径1->5,把它取反,则匹配数增加到1。
(2)找到增广路径2->6,把它取反,则匹配数增加到2。
(3)找到增广路径3->6->2->5->1->4,把它取反,则匹配数增加到3。
(4)再也找不到增广路径,结束。
当然,这只是一种可能的流程。
也可能有别的找增广路径的顺序,或者找到不同的增广路径,最终的匹配方案也可能不一样。
但是最大匹配数一定都是相同的。
对于增广路径还可以用一个递归的方法来描述。
这个描述不一定最准确,但是它揭示了寻找增广路径的一般方法:
“从点A出发的增广路径”一定首先连向一个在原匹配中没有与点A配对的点B。
如果点B在原匹配中没有与任何点配对,则它就是这条增广路径的终点;反之,如果点B已与点C配对,那么这条增广路径就是从A到B,再从B到C,再加上“从点C出发的增广路径”。
并且,这条从C出发的增广路径中不能与前半部分的增广路径有重复的点。
比如图2中,我们要寻找一条从3出发的增广路径,要做以下3步:
(1)首先从3出发,它能连到的点只有6,而6在图1中已经与2配对,所以目前的增广路径就是3->6->2再加上从2出发的增广路径。
(2)从2出发,它能连到的不与前半部分路径重复的点只有5,而且5确实在原匹配中没有与2配对。
所以从2连到5。
但5在图1中已经与1配对,所以目前的增广路径为3->6->2->5->1再加上从1出发的增广路径。
(3)从1出发,能连到的不与自已配对并且不与前半部分路径重复的点只有4。
因为4在图1中没有与任何点配对,所以它就是终点。
所以最终的增广路径是
3->6->2->5->1->4。
但是严格地说,以上过程中从2出发的增广路径(2->5->1->4)和从1出发的增广路径(1->4)并不是真正的增广路径。
因为它们不符合前面讲过的增广路径的第5条性质,它们的起点都是已经配过对的点。
我们在这里称它们为“增广路径”只是为了方便说明整个搜寻的过程。
而这两条路径本身只能算是两个不为外界所知的子过程的返回结果。
显然,从上面的例子可以看出,搜寻增广路径的方法就是DFS,可以写成一个递归函数。
当然,用BFS也完全可以实现。
至此,理论基础部份讲完了。
但是要完成匈牙利算法,还需要一个重要的定理:
如果从一个点A出发,没有找到增广路径,那么无论再从别的点出发找到多少增广路径来改变现在的匹配,从A出发都永远找不到增广路径。
要用文字来证明这个定理很繁,话很难说,要么我还得多画一张图,我在此就省了。
其实你自己画几个图,试图举两个反例,这个定理不难想通的。
(给个提示。
如果你试图举个反例来说明在找到了别的增广路径并改变了现有的匹配后,从A出发就能找到增广路径。
那么,在这种情况下,肯定在找到别的增广路径之前,就能从A出发找到增广路径。
这就与假设矛盾了。
)
有了这个定理,匈牙利算法就成形了。
如下:
初始时最大匹配为空
for 二分图左半边的每个点i
do 从点i出发寻找增广路径。
如果找到,则把它取反(即增加了总了匹
配数)。
如果二分图的左半边一共有n个点,那么最多找n条增广路径。
如果图中共有m 条边,那么每找一条增广路径(DFS或BFS)时最多把所有边遍历一遍,所花时间也就是m。
所以总的时间大概就是O(n * m)。