匹配问题与匈牙利算法和较大基数匹配
- 格式:pdf
- 大小:136.34 KB
- 文档页数:7
匈⽛利算法解决⼆分图最⼤匹配预备知识 匈⽛利算法是由匈⽛利数学家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个剩⼥,每个⼈都可能对多名异性有好感(惊讶,-_-||暂时不考虑特殊的性取向) 如果⼀对男⼥互有好感,那么你就可以把这⼀对撮合在⼀起,现在让我们⽆视掉所有的单相思(好忧伤的感觉,快哭了),你拥有的⼤概就是下⾯这样⼀张关系图,每⼀条连线都表⽰互有好感。
二分图的最大匹配、完美匹配和匈牙利算法August 1, 2013 / 算法这篇文章讲无权二分图(unweighted bipartite graph)的最大匹配(maximum matching)和完美匹配(perfect matching),以及用于求解匹配的匈牙利算法(Hungarian Algorithm);不讲带权二分图的最佳匹配。
二分图:简单来说,如果图中点可以被分为两组,并且使得所有边都跨越组的边界,则这就是一个二分图。
准确地说:把一个图的顶点划分为两个不相交集U和V,使得每一条边都分别连接U、V中的顶点。
如果存在这样的划分,则此图为一个二分图。
二分图的一个等价定义是:不含有「含奇数条边的环」的图。
图 1 是一个二分图。
为了清晰,我们以后都把它画成图 2 的形式。
匹配:在图论中,一个「匹配」(matching)是一个边的集合,其中任意两条边都没有公共顶点。
例如,图3、图 4 中红色的边就是图 2 的匹配。
我们定义匹配点、匹配边、未匹配点、非匹配边,它们的含义非常显然。
例如图 3 中 1、4、5、7 为匹配点,其他顶点为未匹配点;1-5、4-7为匹配边,其他边为非匹配边。
最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。
图 4 是一个最大匹配,它包含 4 条匹配边。
完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。
图 4 是一个完美匹配。
显然,完美匹配一定是最大匹配(完美匹配的任何一个点都已经匹配,添加一条新的匹配边一定会与已有的匹配边冲突)。
但并非每个图都存在完美匹配。
举例来说:如下图所示,如果在某一对男孩和女孩之间存在相连的边,就意味着他们彼此喜欢。
是否可能让所有男孩和女孩两两配对,使得每对儿都互相喜欢呢?图论中,这就是完美匹配问题。
如果换一个说法:最多有多少互相喜欢的男孩/女孩可以配对儿?这就是最大匹配问题。
基本概念讲完了。
二分图匹配题目类型总结二分图最大匹配的匈牙利算法二分图是这样一个图,它的顶点可以分类两个集合X和Y,所有的边关联在两个顶点中,恰好一个属于集合X,另一个属于集合Y。
最大匹配:图中包含边数最多的匹配称为图的最大匹配。
完美匹配:如果所有点都在匹配边上(x=y=m),称这个最大匹配是完美匹配。
最小点覆盖:(二分图)最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。
可以证明:最少的点(即覆盖数)=最大匹配数。
支配集:(二分图)最小点覆盖数+孤立点最小边覆盖:找最大匹配(注意可能是任意图最大匹配)m则有2*m 个点被m 条两两不相交的边覆盖。
对于剩下的n-2*m 个点,每个点用一条边覆盖,总边数为n-m条;最小路径覆盖:用尽量少的不相交简单路径覆盖有向无环图G的所有结点。
解决此类问题可以建立一个二分图模型。
把所有顶点i拆成两个:X结点集中的i和Y结点集中的i',如果有边i->j,则在二分图中引入边i->j',设二分图最大匹配为m,则结果就是n-m。
最大独立集问题:(二分图)n-最小点覆盖;任意图最大匹配:(没有奇环)转换为二分图:把所有顶点i拆成两个:X结点集中的i和Y结点集中的i',如果原图中有边i->j,则在二分图中引入边i-> j',j->i’;设二分图最大匹配为m,则结果就是m/2。
最大完全子图:补图的最大独立集三大博弈问题威佐夫博奕(Wythoff Game):有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
这种情况下是颇为复杂的。
我们用(ak,bk)(ak ≤bk ,k=0,1,2,...,n)表示两堆物品的数量并称其为局势,如果甲面对(0,0),那么甲已经输了,这种局势我们称为奇异局势。
前几个奇异局势是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)。
前言:高中时候老师讲这个就听得迷迷糊糊,有一晚花了通宵看KM的Pascal代码,大概知道过程了,后来老师说不是重点,所以忘的差不多了。
都知道二分图匹配是个难点,我这周花了些时间研究了一下这两个算法,总结一下1.基本概念M代表匹配集合未盖点:不与任何一条属于M的边相连的点交错轨:属于M的边与不属于M的边交替出现的轨(链)可增广轨:两端点是未盖点的交错轨判断M是最大匹配的标准:M中不存在可增广轨2.最大匹配,匈牙利算法时间复杂度:O(|V||E|)原理:寻找M的可增广轨P,P包含2k+1条边,其中k条属于M,k+1条不属于M。
修改M 为M&P。
即这条轨进行与M进行对称差分运算。
所谓对称差分运算,就是比如X和Y都是集合,X&Y=(X并Y)-(x交Y)有一个定理是:M&P的边数是|M|+1,因此对称差分运算扩大了M实现:关于这个实现,有DFS和BFS两种方法。
先列出DFS的代码,带注释。
这段代码来自中山大学的教材核心部分在dfs(x),来寻找可增广轨。
如果找到的话,在Hungarian()中,最大匹配数加一。
这是用了刚才提到的定理。
大家可以想想初始状态是什么,又是如何变化的view plaincopy to clipboardprint?第二种方法BFS,来自我的学长cnhawk核心步骤还是寻找可增广链,过程是:1.从左的一个未匹配点开始,把所有她相连的点加入队列2.如果在右边找到一个未匹配点,则找到可增广链3.如果在右边找到的是一个匹配的点,则看它是从左边哪个点匹配而来的,将那个点出发的所有右边点加入队列这么说还是不容易明白,看代码吧view plaincopy to clipboardprint?3.最佳匹配加权图中,权值最大的最大匹配KM算法:概念:f(v)是每个点的一个值,使得对任意u,v C V,f(u)+f(v)>=w[e u,v]集合H:一个边集,使得H中所有u,v满足f(u)+f(v)=w[e u,v]等价子图:G f(V,H),标有f函数的G图理论:对于f和G f,如果有一个理想匹配集合M p,则M p最优。
指派问题匈牙利算法最大值
指派问题是一个优化问题,旨在确定如何将 n 个任务分配给 n 个人员,以便完成总成本最小或总利润最大。
匈牙利算法是解决指派问题的经典算法之一,通过寻找增广路径来找到最大权值的匹配。
在指派问题中,我们有一个 n x n 的成本矩阵,其中的每个元素表
示将特定任务分配给特定人员的成本或利润。
问题的目标是找到一种分配方式,使得总成本最小或总利润最大。
匈牙利算法是一种基于图论的算法,它通过构建二分图和寻找增广路径来解决指派问题。
算法的核心思想是通过不断改进当前的匹配,直到找到最优解。
具体来说,匈牙利算法的步骤如下:
1. 初始化一个空的匹配集合。
2. 对于每个任务,找到一个未被分配的人员,并将其分配给该任务。
如果该任务没有未被分配的人员,则考虑将其他任务分配给当前人员,并将当前任务分配给其它人员。
3. 如果存在一个未被匹配的任务,寻找一条从该任务出发的增广路径。
增广路径是一条交替经过匹配边和非匹配边的路径,起点和终点都是未匹配的任务。
4. 如果存在增广路径,则改进当前的匹配,即通过将增广路径上的
非匹配边变为匹配边,并将增广路径上的匹配边变为非匹配边。
5. 重复步骤3和步骤4,直到不存在增广路径为止。
匈牙利算法的运行时间复杂度为 O(n^3),其中 n 是任务或人员的数量。
该算法可以找到指派问题的最优解,并且在实践中表现良好。
总之,指派问题是一个重要的优化问题,而匈牙利算法是一种解决指派问题的经典算法。
通过构建二分图并寻找增广路径,匈牙利算法可以找到指派问题的最优解。
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。
一、概述匈牙利算法是一种用于求解二分图最大匹配的经典算法,它的时间复杂度为O(n^3),在实际应用中具有广泛的用途。
本文将通过一个具体的例题,详细介绍利用匈牙利算法求解完美匹配的具体步骤和方法。
二、问题描述假设有一个二分图G=(V, E),其中V={U,V},U={u1,u2,u3},V={v1,v2,v3},E={(u1,v1),(u1,v2),(u2,v2),(u3,v3)},现在希望求解这个二分图的最大匹配。
三、匈牙利算法详解1. 初始化:需要初始化一个大小为|U|的数组match[],用来记录每一个U中的顶点匹配的V中的顶点,初始化为-1,表示初始时没有匹配的顶点。
2. 寻找增广路径:通过遍历U中的每一个顶点,逐个寻找增广路径。
对于每一个未匹配的顶点,都尝试进行增广路径的寻找。
3. 匹配顶点:如果找到了一条增广路径,将增广路径上的顶点逐个匹配,并更新match[]数组。
4. 寻找最大匹配:重复上述步骤,直至无法继续寻找增广路径为止,此时match[]数组中记录的就是二分图的最大匹配。
四、具体例题求解接下来通过一个具体的例题来详细介绍匈牙利算法的求解过程。
假设有一个二分图G=(V, E),其中V={U,V},U={u1,u2,u3},V={v1,v2,v3},E={(u1,v1),(u1,v2),(u2,v2),(u3,v3)}。
首先初始化match[]数组为{-1,-1,-1}。
(1)对u1进行增广路径的寻找由于u1未匹配,从u1开始寻找增广路径。
首先考虑与u1相连的v1和v2。
对v1进行匹配,得到match[0]为1。
对v2进行匹配,得到match[0]为1。
(2)对u2进行增广路径的寻找由于u2未匹配,从u2开始寻找增广路径。
考虑与u2相连的v2。
对v2进行匹配,得到match[1]为2。
(3)对u3进行增广路径的寻找由于u3未匹配,从u3开始寻找增广路径。
考虑与u3相连的v3。
对v3进行匹配,得到match[2]为3。
两个点集配对问题匈牙利算法目录1.引言2.两个点集配对问题的定义和背景3.匈牙利算法的原理和步骤4.匈牙利算法的应用实例5.总结正文1.引言在图论中,点集配对问题(也称为任务分配问题或车辆路径问题)是一个经典的问题。
给定两个点集,分别代表供应点和需求点,我们需要找到一种方式,使得从供应点到需求点的距离总和最小。
匈牙利算法(Hungarian algorithm)是解决这类问题的一种经典算法,它通过不断地寻找最短路径,将供应点与需求点一一对应,使得总距离最小。
2.两个点集配对问题的定义和背景假设我们有两个点集 A 和 B,分别有 m 个供应点和 n 个需求点。
每个供应点可以被分配给任意一个需求点,而每个需求点只能被分配给一个供应点。
我们的目标是找到一种分配方案,使得从每个供应点到其对应的需求点的距离总和最小。
3.匈牙利算法的原理和步骤匈牙利算法的基本思想是:对于没有分配的供应点和需求点,我们寻找一条最短路径,将这两个点连接起来。
这样,我们就可以将问题规模缩小,直到所有的供应点和需求点都被分配。
匈牙利算法的具体步骤如下:(1) 初始化:将所有的供应点和需求点都视为未分配,计算每个供应点到其他所有需求点的距离。
(2) 寻找最短路径:遍历所有的供应点和需求点,找到一条最短路径,将一对供应点和需求点连接起来。
(3) 更新距离:更新已经被连接的供应点和需求点的距离,将它们之间的距离设为 0,同时将其他供应点到这个需求点的距离加 1。
(4) 重复步骤 2 和 3:回到步骤 2,继续寻找最短路径,直到所有的供应点和需求点都被连接。
4.匈牙利算法的应用实例匈牙利算法广泛应用于实际问题中,如物流配送、任务分配、基因匹配等。
其中一个著名的应用实例是旅行商问题(Traveling Salesman Problem, TSP),即给定一组城市和它们之间的距离,我们需要找到一个访问每个城市一次并返回出发点的最短路径。
虽然 TSP 问题目前没有已知的多项式时间算法,但匈牙利算法可以应用于其子问题,如最小生成树问题(Minimum Spanning Tree, MST),帮助我们找到一个较好的解决方案。
一、用匈牙利算法求二分图(二部图,偶图的最大匹配算法中的几个术语说明:1。
二部图:如果图G=(V,E的顶点集何V可分为两个集合X,Y,且满足X∪Y =V, X∩Y=Φ,则G称为二部图;图G的边集用E(G表示,点集用V(G表示。
2。
匹配:设M是E(G的一个子集,如果M中任意两条边在G中均不邻接,则称M是G的一个匹配。
M中的—条边的两个端点叫做在M是配对的。
3。
饱和与非饱和:若匹配M的某条边与顶点v关联,则称M饱和顶点v,并且称v是M-饱和的,否则称v是M-不饱和的。
4。
交互道:若M是二分图G=(V,E的一个匹配。
设从图G中的一个顶点到另一个顶点存在一条道路,这条道路是由属于M的边和不属于M的边交替出现组成的,则称这条道路为交互道。
5。
可增广路:若一交互道的两端点为关于M非饱和顶点时,则称这条交互路是可增广路。
显然,一条边的两端点非饱和,则这条边也是可增广路。
6。
最大匹配:如果M是一匹配,而不存在其它匹配M',使得|M'|>|M|,则称M是最大匹配。
其中|M|表示匹配M的边数。
7。
对称差:A,B是两个集合,定义A⊕B = (A∪B\(A∩B ,则称A⊕B为A和B的对称差。
定理:M为G的最大匹配的充要条件是G中不存在可增广道路。
Hall定理:对于二部图G,存在一个匹配M,使得X的所有顶点关于M饱和的充要条件是:对于X的任意一个子集A,和A邻接的点集为T(A,恒有:|T(A| >= |A|。
匈牙利算法是基于Hall定理中充分性证明的思想,其基本步骤为:1。
任给初始匹配M;2。
若X已饱和则结束,否则进行第3步;3。
在X中找到一个非饱和顶点x0,作V1 ←{x0},V2 ←Φ ;4。
若T(V1 = V2则因为无法匹配而停止,否则任选一点y∈T(V1\V2;5。
若y已饱和则转6,否则做一条从x0→y的可增广路P,M←M⊕E(P,转2;6。
由于y已饱和,所以M中有一条边(y,z,作V1 ←V1∪{z}, V2←V2∪{y},转4;二、用匈牙利算法求二分图的最大匹配(伪代码给定一个二分图(x,y,x中的点和y中点的连接情况,一个匹配是二分图的子图,其中任一个x中的点只能和最多一个y中的点连接,一个y中的点也只能和一个x中的点连接,最大匹配就是使子图中的边数(我们称为匹配边最多的匹配。
两个点集配对问题匈牙利算法摘要:1.两个点集配对问题简介2.匈牙利算法的基本原理3.匈牙利算法的应用场景4.匈牙利算法的优缺点5.实际案例分析正文:在我们的生活中,经常遇到需要将两个点集进行配对的问题,例如在线约会平台为用户推荐匹配的伴侣,或者学校为学生分配宿舍等。
为了解决这类问题,匈牙利算法应运而生。
本文将详细介绍两个点集配对问题、匈牙利算法的基本原理、应用场景以及优缺点。
一、两个点集配对问题简介两个点集配对问题,是指在给定两个点集A和B的情况下,寻找一种最优的配对方式,使得A中的每个点都与B中的一个点配对,且配对数量最大化。
这是一个典型的组合优化问题,可以用图论中的匹配概念来表示。
二、匈牙利算法的基本原理匈牙利算法(Hungarian algorithm),又称霍夫曼编码算法,是由匈牙利数学家Alfréd Rényi和Miklós匈格尔于1957年独立发现的。
该算法基于图论中的最大匹配问题,通过不断地交换相邻顶点来实现最优匹配。
1.将A、B两个点集分别表示为两个矩阵A和B,其中A[:, i]表示A中第i个点的坐标,B[:, j]表示B中第j个点的坐标。
2.计算A和B的匹配矩阵C,C[:, i]表示A中第i个点与B中哪个点匹配。
3.初始化一个长度为A中点数的空矩阵,用于存放已匹配的点。
4.遍历A中的每个点,判断其相邻点是否已匹配,若未匹配,则尝试与B 中未匹配的点进行配对,并更新匹配矩阵C。
5.重复步骤4,直到A和B中的所有点都完成匹配。
6.输出匹配矩阵C,即为最优配对结果。
三、匈牙利算法的应用场景1.任务分配:将一组任务分配给多个人完成,使得每个人的任务量尽量均衡。
2.资源调度:在多个资源供应者和需求者之间分配资源,使得供需平衡且整体效益最大化。
3.生产线调度:将多个生产任务分配给生产线上的机器,使得生产效率最大化。
4.配对问题:如在线约会平台为用户推荐匹配的伴侣,学校为学生分配宿舍等。
⼆分图匹配算法(最⼤流匈⽛利)⼆分图匹配相关概念⽆向⼆分图G(U⋃V,E):U是⼀个顶点集合,V是另⼀个顶点集合,对于⼀个集合内的点⽆边直接相连,⽽对于不同集合的点可以连边,即(u,v)∈E。
匹配:两两不含公共端点的边的集合M称为匹配(就是两个集合之间连的边,只不过不同边的端点不能重合)最⼤匹配:元素最多的M,即⽽G中两两不含公共端点的边的集合M⊆E的基数|M|的最⼤值就是最⼤匹配。
完美匹配:当最⼤匹配的匹配数满⾜2∗|M|=V时,称为完美匹配。
形象的解释就是⼀各集合的所有点到另⼀个集合都有互不相同且唯⼀对应的点。
(类似于函数的双射),想象⼀下图增⼴路:设M为⼆分图G已匹配边的集合,若P是图G中⼀条连通两个未匹配顶点的路径(P的起点在X部,终点在Y部,反之亦可),并且属M的边和不属M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的⼀条增⼴路径。
(就是连了两个还没有配对的顶点的路径,路径有⼀个配对边,⼀个⾮配对边交替组成)更多详细概念解释见匈⽛利部分的参考⽂章最⼤流的⽅法⼆分图的匹配可以看成是⼀种最⼤流问题(这谁想得出来啊)。
具体过程如下:现在有两个点集U和V,之间已经有了写连边,我们需要引⼊⼀个源,⼀个汇,把源跟集合U的所有点有向地连起来,把V的所有点和汇有向地连起来,就构成了⼀个流⽹络。
现在由于⼆分图匹配的限制,⼀个点不能连⾃⼰内部的点(在原来的⼆分图中这关系已经成⽴),不能连两个或多个边。
那么就把每个边的权值赋为⼀。
这样边的流量只有零壹两种,要么有边,要么不连边。
在上⾯跑最⼤流算法即可(具体讲解参见上篇博客)下⾯是代码:代码:#include <iostream>#include <memory.h>#include <vector>#include <queue>#define max_n 10005#define INF 0x3f3f3f3fusing namespace std;//邻接表struct edge{int v;//到达顶点int cap;//最⼤流量int rev;//对应反向边的编号};vector<edge> G[max_n];int level[max_n];//Dinic算法⽤到的层次图int iter[max_n];//当前弧优化void add_edge(int u,int v,int cap){G[u].push_back((edge){v,cap,G[v].size()});//最后⼀个表⽰uv这条边的反向边在G[v]⾥的标号G[v].push_back((edge){u,0,G[u].size()-1});}void bfs(int s)//处理层次图{memset(level,-1,sizeof(level));queue<int> que;level[s] = 0;que.push(s);while(!que.empty()){int v = que.front();que.pop();for(int i = 0;i<G[v].size();i++){edge& e = G[v][i];if(e.cap>0&&level[e.v]<0){level[e.v] = level[v]+1;que.push(v);}}}}int dfs(int v,int t,int f)//Dinic的dfs{if(v==t) return f;for(int& i = iter[v];i<G[v].size();i++){edge& e = G[v][i];if(e.cap>0&&level[e.v]==level[v]+1){int d = dfs(v,t,min(f,e.cap));if(d>0){G[e.v][e.rev].cap+=d;return d;}}}return 0;}int max_flow(int s,int t)//Dinic算法{int flow = 0;for(;;){bfs(s);if(level[t]<0){return flow;}memset(iter,0,sizeof(iter));int f;while(f=dfs(s,t,INF)>0){flow += f;}}}int N,K;//N,K为两个集合的点数bool can[max_n][max_n];//⼆分图中原有的边void solve(){//0~N-1是U中的点//N~N+K-1是V中的点int s = N+K;int t = s+1;for(int i = 0;i<N;i++)//s与U连边{add_edge(s,i,1);}for(int i = 0;i<K;i++)//t与V连边{add_edge(i+N,t,1);}for(int i = 0;i<N;i++){for(int j = 0;j<K;j++){if(can[i][j]){add_edge(i,j,1);//⼆分图原有边的链接}}}cout << max_flow(s,t) << endl;//求最⼤流即得最⼤匹配}int main(){cin >> N >> K;solve();return 0;}匈⽛利算法这个算法是专门处理⼆分图的最⼤匹配问题的,有很好的博客讲解,下⾯是推荐阅读⽅式:我上⾯的概念可能不太全,那就先来看看⼆分图的相关概念:可能还对增⼴路径不是很理解,什么是增⼴路,⾮配对配对交替什么的很混乱,那不妨先看看这个:现在到了算法流程了,在正式介绍前,先有个有趣⽽深刻的认识,下⾯是⼗分清晰的讲解:好了,该正式⼀点了,相信你也有了⼀定的了解:上⾯的代码其实已经够清晰了,如果还想看⼀下,就这篇吧:代码:#include <iostream>#include <memory.h>#define max_n 200005using namespace std;int n,m;int con_y[max_n];int visit[max_n];int head[max_n];struct edge{int v;int nxt;}e[max_n<<1];int cnt = 0;void add(int u,int v){++cnt;e[cnt].v = v;e[cnt].nxt = head[u];head[u] = cnt;}int dfs(int u){for(int i = head[u];i;i=e[i].nxt){int v = e[i].v;if(visit[v]==0){if(con_y[v]==-1||dfs(v))//结合上⾯算法流程部分的有趣博客再理解了⼀下这⾥的递归,好奇妙 {con_x[u] = v;con_y[v] = u;return 1;}}}return 0;}int Hungary(){memset(con_x,-1,sizeof(con_x));memset(con_y,-1,sizeof(con_y));int ans = 0;for(int i = 1;i<=n;i++){memset(visit,0,sizeof(visit));ans += dfs(i);}return ans;}int main(){cin >> n >> m;for(int i = 1;i<=m;i++){int a,b,c;cin >> a >> b;add(a,b);}cout << Hungary() << endl;return 0;}参考⽂章以上Processing math: 100%。
匈牙利匹配算法步骤匈牙利匹配算法是一种求解二分图最大匹配问题的高效算法。
它由匈牙利数学家Eduard Czuber和König于1931年提出,后被Kuhn在1955年重新发现并加以改进。
该算法能够解决许多实际问题,如婚配问题、任务分配问题等。
本文将详细介绍匈牙利匹配算法的步骤。
首先,我们需要理解什么是二分图和匹配。
一个二分图是由两个不相交的集合V1和V2构成的图,其中每条边都连接着V1中的一个顶点和V2中的一个顶点。
而一个匹配则是图中的一组边,这些边两两之间没有公共顶点。
最大匹配是指在所有可能的匹配中,包含的边数最多的匹配。
接下来,我们来看看匈牙利匹配算法的具体步骤:1. 初始化:为每个顶点v赋予一个权值d(v) = 0。
2. 找增广路径:从一个未匹配的顶点u开始,寻找一条增广路径P。
这条路径的特点是:它的起点是未匹配的顶点,终点是未匹配的顶点,且路径上的边交替地属于匹配M和不属于匹配M。
3. 更新权值:如果找到了增广路径P,那么就更新路径上所有顶点的权值。
具体来说,对于路径上的每一个顶点v,有以下两种情况:- 如果v是一个奇顶点(即在路径P中位置为奇数),则令d(v) = d(v) + 1。
- 如果v是一个偶顶点(即在路径P中位置为偶数),则令d(v) = d(v) - 1。
4. 检查是否结束:如果找不到增广路径了,那么算法结束;否则回到第二步继续找增广路径。
以上就是匈牙利匹配算法的主要步骤。
这个算法的基本思想是通过不断地找增广路径和更新权值,使得最后能找到一个最大的匹配。
匈牙利匹配算法的优点在于它的效率高。
在最坏的情况下,匈牙利匹配算法的时间复杂度是O(n^3),其中n是图中顶点的数量。
而在实际情况中,由于可以使用各种优化技巧,例如使用数据结构来加速查找增广路径的过程,所以通常情况下算法的运行时间会远小于理论上的最坏情况。
此外,匈牙利匹配算法还有很好的可扩展性。
它可以很容易地推广到一些更复杂的问题,例如带权重的最大匹配问题、多对多匹配问题等。
匈⽛利算法解决两个坐标列表匹配的问题遇到⼀个问题,有⼀个坐标列表A:[[10,20],[20,30],[42,41]],和⼀个坐标列表B:[[14,24],[41,42],[20,31],[42,41]],需要看这两个坐标列表之间谁与谁更加匹配,这时候就可以使⽤匈⽛利算法来实现。
原理不再赘述,直接显⽰代码:from scipy.optimize import linear_sum_assignmentimport numpy as np# 先前的坐标position_a = [[10,20],[20,30],[42,41]]# 之后的坐标position_b = [[14,24],[41,42],[20,31],[42,41]]# 使⽤坐标计算代价矩阵cost_matrix = [[np.power((np.array(a)-np.array(b)),2).sum() for a in position_a] for b in position_b ]print("代价矩阵")print(cost_matrix)# 进⾏匈⽛利算法匹配row_ind, col_ind = linear_sum_assignment(cost_matrix)for x,y in zip(row_ind, col_ind):print("列表B中的%s,应该与列表A中坐标%s匹配,距离消耗为%d"%(position_b[x],position_a[y],cost_matrix[x][y]))结果:代价矩阵[[32, 72, 1073], [1445, 585, 2], [221, 1, 584], [1465, 605, 0]]列表B中的[14, 24],应该与列表A中坐标[10, 20]匹配,距离消耗为32列表B中的[20, 31],应该与列表A中坐标[20, 30]匹配,距离消耗为1列表B中的[42, 41],应该与列表A中坐标[42, 41]匹配,距离消耗为0。