匈牙利算法和KM算法简介
最大化指派问题匈牙利算法
![最大化指派问题匈牙利算法](https://img.taocdn.com/s3/m/f99b541fbf23482fb4daa58da0116c175f0e1ed9.png)
最大化指派问题匈牙利算法匈牙利算法,也称为Kuhn-Munkres算法,是用于解决最大化指派问题(Maximum Bipartite Matching Problem)的经典算法。
最大化指派问题是在一个二分图中,找到一个匹配(即边的集合),使得匹配的边权重之和最大。
下面我将从多个角度全面地介绍匈牙利算法。
1. 算法原理:匈牙利算法基于增广路径的思想,通过不断寻找增广路径来逐步扩展匹配集合,直到无法找到增广路径为止。
算法的基本步骤如下:初始化,将所有顶点的标记值设为0,将匹配集合初始化为空。
寻找增广路径,从未匹配的顶点开始,依次尝试匹配与其相邻的未匹配顶点。
如果找到增广路径,则更新匹配集合;如果无法找到增广路径,则进行下一步。
修改标记值,如果无法找到增广路径,则通过修改标记值的方式,使得下次寻找增广路径时能够扩大匹配集合。
重复步骤2和步骤3,直到无法找到增广路径为止。
2. 算法优势:匈牙利算法具有以下优势:时间复杂度较低,匈牙利算法的时间复杂度为O(V^3),其中V是顶点的数量。
相比于其他解决最大化指派问题的算法,如线性规划算法,匈牙利算法具有更低的时间复杂度。
可以处理大规模问题,由于时间复杂度较低,匈牙利算法可以处理大规模的最大化指派问题,而不会因为问题规模的增加而导致计算时间大幅增加。
3. 算法应用:匈牙利算法在实际中有广泛的应用,例如:任务分配,在人力资源管理中,可以使用匈牙利算法将任务分配给员工,使得任务与员工之间的匹配最优。
项目分配,在项目管理中,可以使用匈牙利算法将项目分配给团队成员,以最大程度地提高团队成员与项目之间的匹配度。
资源调度,在物流调度中,可以使用匈牙利算法将货物分配给合适的运输车辆,使得货物与运输车辆之间的匹配最优。
4. 算法扩展:匈牙利算法也可以扩展到解决带权的最大化指派问题,即在二分图的边上赋予权重。
在这种情况下,匈牙利算法会寻找一个最优的匹配,使得匹配边的权重之和最大。
匈牙利算法和KM算法简介
![匈牙利算法和KM算法简介](https://img.taocdn.com/s3/m/2149548c77a20029bd64783e0912a21615797f77.png)
KM算法
❖ 穷举旳效率-n!,我们需要愈加优异旳算法。 ❖ 定理: ❖ 设M是一种带权完全二分图G旳一种完备匹配,给
每个顶点一种可行顶标(第i个x顶点旳可行标用lx[i] 表达,第j个y顶点旳可行标用ly[j]表达),假如对全 部旳边(i,j) in G,都有lx[i]+ly[j]>=w[i,j]成立(w[i,j]表达 边旳权),且对全部旳边(i,j) in M,都有lx[i]+ly[j]=w[i,j] 成立,则M是图G旳一种最佳匹配。证明很轻易。
KM算法
❖ 对于任意旳G和M,可行顶标都是存在旳:
❖ l(x) = maxw(x,y)
❖ l(y) = 0 ❖ 欲求完全二分图旳最佳匹配,只要用匈牙利算法求
其相等子图旳完备匹配;问题是当标号之后旳Gl无 完备匹配时怎么办?1957年(居然比匈牙利算法 早???),Kuhn和Munkras给出了一种处理该问 题旳有效算法,用逐次修改可行顶标l(v)旳方法使相 应旳相等子图之最大匹配逐次增广,最终出现完备 匹配。
KM算法
❖ 修改措施如下:
❖ 先将一种未被匹配旳顶点u(u in {x})做一次增广路, 记下哪些结点被访问那些结点没有被访问。求出 d=min{lx[i]+ly[j]-w[i,j]}其中i结点被访问,j结点没有 被访问。然后调整lx和ly:对于访问过旳x顶点,将 它旳可行标减去d,对于全部访问过旳y顶点,将它 旳可行标增长d。修改后旳顶标仍是可行顶标,原 来旳匹配M依然存在,相等子图中至少出现了一条 不属于M旳边,所以造成M旳逐渐增广。
Empty Grass Wall
例题1 Place the Robots(ZOJ)
模型一
在问题旳原型中,草地,墙这些信 息不是我们所关心旳,我们关心旳 只是空地和空地之间旳联络。所以, 我们很自然想到了下面这种简朴旳 模型:
BipartiteGraph
![BipartiteGraph](https://img.taocdn.com/s3/m/39b35cde5022aaea998f0f00.png)
1 2
5
3 4
1
2
3
4
由于每条边表示一个空地,有冲 突的空地之间必有公共顶点,所 以问题转化为二部图的最大匹配 问题。
1
2
3
4
例题1 Place the Robots(ZOJ)
小结
比较前面的两个模型:模型一过于简单,没有给问 题的求解带来任何便利;模型二则充分抓住了问题的内 在联系,巧妙地建立了二部图模型。为什么会产生这种 截然不同的结果呢?其一是由于对问题分析的角度不同: 模型一以空地为点,模型二以空地为边;其二是由于对 原型中要素的选取有差异:模型一对要素的选取不充分, 模型二则保留了原型中“棋盘”这个重要的性质。由此 可见,对要素的选取,是图论建模中至关重要的一步。
二分图匹配
匈牙利算法和KM算法简介
二分图的概念
二分图又称作二部图,是图论中的一种特殊
模型。 设G=(V,{R})是一个无向图。如顶点集V可分 割为两个互不相交的子集,并且图中每条边 依附的两个顶点都分属两个不同的子集。则 1 2 3 4 5 称图G为二分图。
1
2
3
4
最大匹配
给定一个二分图G,在G的一个子图M中,M
1
2 3
4
1 3 8 5 7 2
8 7 6 5
4
这是NP问题!
6
例题1 Place the Robots(ZOJ)
模型二
我们将每一行,每一列被墙隔开, 且包含空地的连续区域称作 “块”。显然,在一个块之中, 最多只能放一个机器人。我们把 这些块编上号。
1 2
5
3 4
同样,把竖直方向的块也编上号。
1
KM算法
算法学习:图论之二分图的最优匹配(KM算法)
![算法学习:图论之二分图的最优匹配(KM算法)](https://img.taocdn.com/s3/m/27bf2f09581b6bd97f19ea53.png)
二分图的最优匹配(KM算法)KM算法用来解决最大权匹配问题:在一个二分图内,左顶点为X,右顶点为Y,现对于每组左右连接XiYj有权wij,求一种匹配使得所有wij的和最大。
基本原理该算法是通过给每个顶点一个标号(叫做顶标)来把求最大权匹配的问题转化为求完备匹配的问题的。
设顶点Xi的顶标为A[ i ],顶点Yj的顶标为B[ j ],顶点Xi与Yj之间的边权为w[i,j]。
在算法执行过程中的任一时刻,对于任一条边(i,j),A[ i ]+B[j]>=w[i,j]始终成立。
KM算法的正确性基于以下定理:若由二分图中所有满足A[ i ]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最大权匹配。
首先解释下什么是完备匹配,所谓的完备匹配就是在二部图中,X点集中的所有点都有对应的匹配或者是Y点集中所有的点都有对应的匹配,则称该匹配为完备匹配。
这个定理是显然的。
因为对于二分图的任意一个匹配,如果它包含于相等子图,那么它的边权和等于所有顶点的顶标和;如果它有的边不包含于相等子图,那么它的边权和小于所有顶点的顶标和。
所以相等子图的完备匹配一定是二分图的最大权匹配。
初始时为了使A[ i ]+B[j]>=w[i,j]恒成立,令A[ i ]为所有与顶点Xi关联的边的最大权,B[j]=0。
如果当前的相等子图没有完备匹配,就按下面的方法修改顶标以使扩大相等子图,直到相等子图具有完备匹配为止。
我们求当前相等子图的完备匹配失败了,是因为对于某个X顶点,我们找不到一条从它出发的交错路。
这时我们获得了一棵交错树,它的叶子结点全部是X顶点。
现在我们把交错树中X顶点的顶标全都减小某个值d,Y顶点的顶标全都增加同一个值d,那么我们会发现:1)两端都在交错树中的边(i,j),A[ i ]+B[j]的值没有变化。
也就是说,它原来属于相等子图,现在仍属于相等子图。
2)两端都不在交错树中的边(i,j),A[ i ]和B[j]都没有变化。
数学建模匈牙利算法
![数学建模匈牙利算法](https://img.taocdn.com/s3/m/22d7857611661ed9ad51f01dc281e53a59025168.png)
数学建模匈牙利算法
【最新版】
目录
一、匈牙利算法的概念与基本原理
二、匈牙利算法的应用实例
三、匈牙利算法的优缺点
正文
一、匈牙利算法的概念与基本原理
匈牙利算法(Hungarian algorithm)是一种求解二分图最大匹配问题的算法,由匈牙利数学家 Mátyásovszky 于 1937 年首次提出。
该算法的基本思想是:通过不断循环寻找图中的偶数长度路径,并将路径中的顶点依次匹配,直到找不到这样的路径为止。
此时,图中的所有顶点都已匹配,即得到了二分图的最大匹配。
二、匈牙利算法的应用实例
匈牙利算法广泛应用于任务分配、资源调度、数据融合等领域。
下面举一个简单的例子来说明匈牙利算法的应用。
假设有 5 个工人和 8 个任务,每个工人完成不同任务的效率不同。
我们需要为每个任务分配一个工人,使得总效率最大。
可以用一个二分图来表示这个问题,其中顶点分为两类:工人和任务。
边表示任务与工人之间的效率关系。
匈牙利算法可以用来求解这个问题,找到最优的任务分配方案。
三、匈牙利算法的优缺点
匈牙利算法的优点是简单、高效,可以解决二分图的最大匹配问题。
然而,它也存在一些缺点:
1.匈牙利算法只能解决无向图的匹配问题,对于有向图,需要将其转
换为无向图才能使用匈牙利算法。
2.当图中存在环时,匈牙利算法无法找到最大匹配。
这时需要使用其他算法,如 Euclidean algorithm(欧几里得算法)来解决。
3.匈牙利算法在实际应用中可能存在数值稳定性问题,即在计算过程中可能出现精度误差。
二分图匹配――匈牙利算法和KM算法简介.
![二分图匹配――匈牙利算法和KM算法简介.](https://img.taocdn.com/s3/m/6b3d4e76561252d380eb6ef4.png)
KM算法
对于任意的G和M,可行顶标都是存在的: l(x) = maxw(x,y) l(y) = 0 欲求完全二分图的最佳匹配,只要用匈牙利算法求 其相等子图的完备匹配;问题是当标号之后的Gl无 完备匹配时怎么办?1957年(居然比匈牙利算法 早???),Kuhn和Munkras给出了一个解决该问 题的有效算法,用逐次修改可行顶标l(v)的办法使对 应的相等子图之最大匹配逐次增广,最后出现完备 匹配。
二分图匹配
匈牙利算法和KM算法简介
二分图的概念
二分图又称作二部图,是图论中的一种特殊
模型。 设G=(V,{R})是一个无向图。如顶点集V可分 割为两个互不相交的子集,并且图中每条边 依附的两个顶点都分属两个不同的子集。则 1 2 3 4 5 称图G为二分图。
1
2
3
4
最大匹配
给定一个二分图G,在G的一个子图M中,M
的边集{E}中的任意两条边都不依附于同一个 顶点,则称M是一个匹配。 选择这样的边数最大的子集称为图的最大匹 配问题(maximal matching problem) 如果一个匹配中,图中的每个顶点都和图中 某条边相关联,则称此匹配为完全匹配,也 称作完备匹配。
匈牙利算法
求最大匹配的一种显而易见的算法是:先找出全部 匹配,然后保留匹配数最多的。但是这个算法的复 杂度为边数的指数级函数。因此,需要寻求一种更 加高效的算法。 增广路的定义(也称增广轨或交错轨): 若P是图G中一条连通两个未匹配顶点的路径,并且 属M的边和不属M的边(即已匹配和待匹配的边)在P 上交替出现,则称P为相对于M的一条增广路径。
KM算法
穷举的效率-n!,我们需要更加优秀的算法。 定理: 设M是一个带权完全二分图G的一个完备匹配,给 每个顶点一个可行顶标(第i个x顶点的可行标用lx[i] 表示,第j个y顶点的可行标用ly[j]表示),如果对所 有的边(i,j) in G,都有lx[i]+ly[j]>=w[i,j]成立(w[i,j]表示 边的权),且对所有的边(i,j) in M,都有lx[i]+ly[j]=w[i,j] 成立,则M是图G的一个最佳匹配。证明很容易。
匈牙利算法
![匈牙利算法](https://img.taocdn.com/s3/m/7a6e637328ea81c759f57894.png)
匈牙利算法匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名。
匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。
在介绍匈牙利算法之前还是先提一下几个概念,下面M是G的一个匹配。
M-交错路:p是G的一条通路,如果p中的边为属于M中的边与不属于M但属于G中的边交替出现,则称p是一条M-交错路。
如:路径(X3,Y2,X1,Y4),(Y1,X2,Y3)。
M-饱和点:对于v∈V(G),如果v与M中的某条边关联,则称v 是M-饱和点,否则称v是非M-饱和点。
如X1,X2,Y1,Y2都属于M-饱和点,而其它点都属于非M-饱和点。
M-可增广路:p是一条M-交错路,如果p的起点和终点都是非M-饱和点,则称p为M-可增广路。
如(X3,Y2,X1,Y4)。
(不要和流网络中的增广路径弄混了)求最大匹配的一种显而易见的算法是:先找出全部匹配,然后保留匹配数最多的。
但是这个算法的时间复杂度为边数的指数级函数。
因此,需要寻求一种更加高效的算法。
下面介绍用增广路求最大匹配的方法(称作匈牙利算法,匈牙利数学家Edmonds于1965年提出)。
增广路的定义(也称增广轨或交错轨):若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。
由增广路的定义可以推出下述三个结论:1-P的路径个数必定为奇数,第一条边和最后一条边都不属于M。
2-将M和P进行取反操作可以得到一个更大的匹配M'。
3-M为G的最大匹配当且仅当不存在M的增广路径。
算法轮廓:⑴置M为空⑵找出一条增广路径P,通过异或操作获得更大的匹配M'代替M⑶重复⑵操作直到找不出增广路径为止折叠。
最大匹配算法(匈牙利算法)
![最大匹配算法(匈牙利算法)](https://img.taocdn.com/s3/m/7bc1f1f8941ea76e58fa043d.png)
最小路径覆盖
将n个点拆成2n个点,如1号变为1和1’, 1代表出边,1’代表进边。对于每个结点, 将与其相临的边连出来。 对已经连好的图求最大匹配数
最小路径覆盖
最小路径覆盖数=顶点数n-最大匹配数
Nkoj 1684 1465 1681 1070
courses Taxi Cab Scheme Girls and boys 信和信封的问题
一张残缺的棋盘,用1*2的矩形去覆盖它, 要求矩形不互相重叠棋盘染成黑白相间,黑色方格作为左 边的点,白色方格作为右边的点,相邻 的黑白方格中间连一条边。 对已经建好的图求最大匹配
二分图的最大独立数
最大独立数=最大匹配数
最小路径覆盖
一张图n个点,给定某些点之间可以用线 连起来。 问最少画多少笔才能将所有的点全部盖 住 poj1422
二分图的最小覆盖数
棋盘上有N个点,每次可以拿走一行或者 一列。 问最少多少次可以把棋盘上的所有点都 拿走
poj3041
二分图的最小覆盖数
将行作为左边的点,列作为右边的点, 原图中的每个点形成一条边,将代表其 行和列的点连接起来。 对已经建好的图求最大匹配
Konig定理
最大匹配数=最小覆盖数
二分图的最大独立数
二分图的 最大匹配
RCA
二分图
1
二分图是一种特殊的图 对于无向图G=(V,E),如 果V可以分为两个互不相 交的子集,并且图中的每 条边所依附的两点都属于 不同的子集,则图G则称 为一个二分图
1’ 2 2’ 3 3’ 4 4’ 5
最大匹配
给定一个二分图G,在G的一个子图的边 集中的任意两条边都不依附于同一个顶 点,则称此子图是一个匹配。 选择这样的边数最大的子集称为图的最 最 大匹配问题(maximal matching problem) 大匹配问题 如果一个匹配中,图中的每个顶点都和 图中某条边相关联,则称此匹配为完全 完全 匹配,也称作完备匹配。 完备匹配。 匹配 完备匹配
匈牙利算法——精选推荐
![匈牙利算法——精选推荐](https://img.taocdn.com/s3/m/ce852839443610661ed9ad51f01dc281e53a56ef.png)
二分图最优匹配:对于二分图的每条边都有一个权(非负),要求一种完备匹配方案,使得所有匹配边的权和最大,记做最优完备匹配。
(特殊的,当所有边的权为1时,就是最大完备匹配问题)解二分图最优匹配问题可用穷举的方法,但穷举的效率=n!,所以我们需要更加优秀的算法。
先说一个定理:设M是一个带权完全二分图G的一个完备匹配,给每个顶点一个可行顶标(第i个x顶点的可行标用lx[i]表示,第j个y顶点的可行标用ly[j]表示),如果对所有的边(i,j) in G,都有lx[i]+ly[j]>=w[i,j]成立(w[i,j]表示边的权),且对所有的边(i,j) in M,都有lx[i]+ly[j]=w[i,j]成立,则M是图G的一个最优匹配。
Kuhn-Munkras算法(即KM算法)流程:v(1)初始化可行顶标的值v(2)用匈牙利算法寻找完备匹配v(3)若未找到完备匹配则修改可行顶标的值v(4)重复(2)(3)直到找到相等子图的完备匹配为止KM算法主要就是控制怎样修改可行顶标的策略使得最终可以达到一个完美匹配,首先任意设置可行顶标(如每个X节点的可行顶标设为它出发的所有弧的最大权,Y节点的可行顶标设为0),然后在相等子图中寻找增广路,找到增广路就沿着增广路增广。
而如果没有找到增广路呢,那么就考虑所有现在在匈牙利树中的X节点(记为S集合),所有现在在匈牙利树中的Y节点(记为T 集合),考察所有一段在S集合,一段在not T集合中的弧,取delta = min {l(xi)+l(yj)-w(xi,yj) , | xi in S, yj in not T} 。
明显的,当我们把所有S集合中的l(xi)减少delta之后,一定会有至少一条属于(S, not T)的边进入相等子图,进而可以继续扩展匈牙利树,为了保证原来属于(S,T )的边不退出相等子图,把所有在T 集合中的点的可行顶标增加delta。
随后匈牙利树继续扩展,如果新加入匈牙利树的Y节点是未盖点,那么找到增广路,否则把该节点的对应的X匹配点加入匈牙利树继续尝试增广。
匈牙利算法
![匈牙利算法](https://img.taocdn.com/s3/m/e9b1204a4afe04a1b171dea1.png)
匈牙利算法是一种用于在多项式时间内解决任务分配问题的组合优化算法,它推广了后来的原始对偶方法。
美国数学家哈罗德·库恩(Harold Kuhn)于1955年提出了该算法。
该算法之所以称为匈牙利算法,是因为该算法的很大一部分是基于前匈牙利数学家DéNESKőnig和Jenőegerváry的工作。
概念在介绍匈牙利算法之前,我想介绍一些概念。
接下来的M是G 的匹配项。
如果是,则边缘已经在匹配的M上。
M交织路径:P是G的路径。
如果P中的边缘是属于m的边缘,而不属于m但属于G的边缘是交替的,则p是M交织的路径。
例如:路径。
M饱和点:例如,如果V与M中的边相关联,则称V为m饱和,否则V为非m饱和。
如果它们全部属于m饱和点,则其他点都属于非m饱和点。
M扩展路径:P是m隔行扫描路径。
如果P的起点和终点均为非m饱和点,则p称为m增强路径。
例如(不要与流网络中的扩展路径混淆)。
寻找最大匹配数的一种显而易见的算法是先找到所有匹配项,然后保留匹配数最大的匹配项。
但是该算法的时间复杂度是边数的指数函数。
因此,我们需要找到一种更有效的算法。
本文介绍了一种使用扩展路径查找最大匹配的方法(称为匈牙利算法,由匈牙利的Edmonds于1965年提出)。
增强导轨(也称为增强导轨或交错导轨)的定义如果P是连接图G中两个不匹配顶点的路径,并且属于m和不属于m的边缘(即,匹配边缘和待匹配边缘)在P上交替,则p称为相对于M.从增强路径的定义可以得出三个结论(1)P的路径数必须为奇数,并且第一个边缘和最后一个边缘都不属于M。
(2)通过将m和P取反可以获得更大的匹配度。
(3)当且仅当没有M的增强路径时,M是G的最大匹配。
算法概述:(1)将M设置为null(2)通过XOR操作找到扩展路径P并获得更大的匹配项而不是m(3)重复(2),直到找不到增强路径。
匈牙利算法简介
![匈牙利算法简介](https://img.taocdn.com/s3/m/9e696aef856a561252d36f50.png)
匈牙利算法匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名。
匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。
设G=(V,E)是一个无向图。
如顶点集V可分割为两个互不相交的子集V1,V2之并,并且图中每条边依附的两个顶点都分属于这两个不同的子集。
则称图G 为二分图。
二分图也可记为G=(V1,V2,E)。
给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
选择这样的子集中边数最大的子集称为图的最大匹配问题(maximal matching problem)如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备,完美匹配。
编辑本段算法描述求最大匹配的一种显而易见的算法是:先找出全部匹配,然后保留匹配数最多的。
但是这个算法的时间复杂度为边数的指数级函数。
因此,需要寻求一种更加高效的算法。
下面介绍用增广路求最大匹配的方法(称作匈牙利算法,匈牙利数学家Edmonds于1965年提出)。
增广路的定义(也称增广轨或交错轨):若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。
由增广路的定义可以推出下述三个结论:1-P的路径个数必定为奇数,第一条边和最后一条边都不属于M。
2-将M和P进行取反操作可以得到一个更大的匹配M’。
3-M为G的最大匹配当且仅当不存在M的增广路径。
算法轮廓:(1)置M为空(2)找出一条增广路径P,通过异或操作获得更大的匹配M’代替M(3)重复(2)操作直到找不出增广路径为止编辑本段时间空间复杂度时间复杂度邻接矩阵:最坏为O(n^3) 邻接表:O(mn)空间复杂度邻接矩阵:O(n^2) 邻接表:O(m+n)邻接表-C++#include <iostream>#include <cstring>using namespace std;//定义链表struct link{int data; //存放数据link* next; //指向下一个节点link(int=0);};link::link(int n){data=n;next=NULL;}int n1,n2,m,ans=0;int result[101]; //记录n1中的点匹配的点的编号//?????????????????????????????????pass 一一对应保存结果bool state [101]; //记录n1中的每个点是否被搜索过link *head [101]; //记录n2中的点的邻接节点link *last [101]; //邻接表的终止位置记录//判断能否找到从节点n开始的增广路bool find(const int n){link* t=head[n];while (t!=NULL) //n仍有未查找的邻接节点时{if (!(state[t->data])) //如果邻接点t->data未被查找过{state[t->data]=true; //标记t->data为已经被找过if ((result[t->data]==0) || //如果t->data不属于前一个匹配M(find(result[t->data]))) //如果t->data匹配到的节点可以寻找到增广路????????????????????pass{result[t->data]=n; //那么可以更新匹配M',其中n1中的点t->data匹配n return true; //返回匹配成功的标志}}t=t->next; //继续查找下一个n的邻接节点}return false;}int main(){int t1=0, t2=0;cin>>n1>>n2>>m;for (int i=0; i<m; i++){cin>>t1>>t2;if (last[t1]==NULL)last[t1]=head[t1]=new link(t2);elselast[t1]=last[t1]->next=new link(t2);}for (int i=1; i<=n1; i++){memset(state, 0, sizeof(state));if (find(i)) ans++;}cout<<ans<<endl;return 0;}邻接矩阵——C++第一个节点的flag不就一直是零了吗#include<iostream>#include<cstring>using namespace std;int map[105][105];int visit[105],flag[105];int n,m;bool dfs(int a){for(int i=1;i<=n;i++){if(map[a][i] && !visit[i]){visit[i]=1;//设置visit标识保证不出现1匹配2的情况?还是为了省事,这个节点如果可以增广,下面就把它增广了,不能的话,以后也就别费劲,把它忽略吧。
图论二分图匹配算法详细分析总结
![图论二分图匹配算法详细分析总结](https://img.taocdn.com/s3/m/d8afabd7b14e852458fb5785.png)
二分图匹配算法总结 (by phoenixinter, Aug 2006)最近下决心要把二分图匹配部分的算法都搞搞清楚,努力了几天之后基本上搞定了,下面做一个这个专题的总结。
一、二分图最大匹配二分图最大匹配的经典匈牙利算法是由Edmonds在1965年提出的,算法的核心就是根据一个初始匹配不停的找增广路,直到没有增广路为止。
匈牙利算法的本质实际上和基于增广路特性的最大流算法还是相似的,只需要注意两点:(一)每个X节点都最多做一次增广路的起点;(二)如果一个Y节点已经匹配了,那么增广路到这儿的时候唯一的路径是走到Y节点的匹配点(可以回忆最大流算法中的后向边,这个时候后向边是可以增流的)。
找增广路的时候既可以采用dfs也可以采用bfs,两者都可以保证O(nm)的复杂度,因为每找一条增广路的复杂度是O(m),而最多增广n次,dfs在实际实现中更加简短。
二、Hopcroft-Karp算法SRbGa很早就介绍过这个算法,它可以做到O(sqrt(n)*e)的时间复杂度,并且在实际使用中效果不错而且算法本身并不复杂。
Hopcroft-Karp算法是Hopcroft和Karp在1972年提出的,该算法的主要思想是在每次增广的时候不是找一条增广路而是同时找几条点不相交的最短增广路,形成极大增广路集,随后可以沿着这几条增广路同时进行增广。
可以证明在寻找增广路集的每一个阶段所寻找到的最短增广路都具有相等的长度,并且随着算法的进行最短增广路的长度是越来越长的,更进一步的分析可以证明最多只需要增广ceil(sqrt(n))次就可以得到最大匹配(证明在这里略去)。
因此现在的主要难度就是在O(e)的时间复杂度内找到极大最短增广路集,思路并不复杂,首先从所有X的未盖点进行BFS,BFS之后对每个X节点和Y节点维护距离标号,如果Y节点是未盖点那么就找到了一条最短增广路,BFS完之后就找到了最短增广路集,随后可以直接用DFS对所有允许弧(dist[y]=dist[x]+ 1,可以参见高流推进HLPP的实现)进行类似于匈牙利中寻找增广路的操作,这样就可以做到O(m)的复杂度。
匈牙利算法 描述
![匈牙利算法 描述](https://img.taocdn.com/s3/m/46b1ed7030126edb6f1aff00bed5b9f3f90f72aa.png)
匈牙利算法描述匈牙利算法是一种用于解决二分图最大匹配问题的算法,它由匈牙利数学家DénesKőnig和JenőEgerváry于1930年代开发而成。
该算法的主要用途是在给定一个二分图后,找出其最大的匹配,即找到最大的匹配顶点对,使得图中的边连接了尽可能多的顶点。
匈牙利算法在组合优化、网络流、计算几何等领域都有广泛的应用。
一、匈牙利算法原理匈牙利算法的基本原理是通过不断增广现有的匹配来逐步找到最大匹配。
在算法执行的过程中,它会不断尝试改进当前的匹配,找到更多的匹配边,直到无法再增广为止。
匈牙利算法是通过交替路径来实现增广匹配的。
在每一轮中,它会选择一个未匹配的起始顶点,并试图在图中找到一条交替路径,这条路径的定义是一种交替的交错顶点序列,其中相邻的两个顶点分别属于两条不相交的边。
找到这样的交替路径后,就可以通过将原匹配中的所选路径上的所有边的匹配状态进行交换,来增大当前的匹配数,如此不断重复直到无法再找到增广路径为止。
在匈牙利算法的执行过程中,需要着重考虑如何找到一条增广路径,以及如何有效地交换匹配。
通过合适的优化策略,匈牙利算法可以在较短的时间内找到最大匹配。
二、匈牙利算法步骤实际应用匈牙利算法时,通常会按照以下步骤来执行:1. 初始化:首先将所有顶点标记为未访问状态,并设置所有匹配为未知。
然后从第一个顶点开始,尝试寻找从该顶点出发的增广路径。
2. 寻找增广路径:从未匹配的顶点开始,逐一尝试寻找增广路径。
如果找到了增广路径,则将原来的匹配进行交换;如果找不到增广路径,则执行第4步。
3. 重标记:如果无法找到增广路径,需要对当前的标记状态进行调整,重新寻找增广路径。
4. 完成匹配:当无法再找到增广路径时,当前的匹配即为最大匹配,算法结束。
在实际的算法实现中,还可以通过一些优化措施来提高匈牙利算法的效率,例如路径压缩、节点标记等。
这些优化措施可以进一步提高算法的运行效率,使得匈牙利算法可以应用到更大规模的问题中。
K M 算 法 详 解 ( 2 0 2 0 )
![K M 算 法 详 解 ( 2 0 2 0 )](https://img.taocdn.com/s3/m/5090a766fab069dc5122019e.png)
【原创】我的KM算法详解0.二分图二分图的概念二分图又称作二部图,是图论中的一种特殊模型。
设G=(V, E)是一个无向图。
如果顶点集V可分割为两个互不相交的子集X和Y,并且图中每条边连接的两个顶点一个在X中,另一个在Y中,则称图G为二分图。
可以得到线上的driver与order之间的匹配关系既是一个二分图。
二分图的判定无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。
判断无向连通图是不是二分图,可以使用深度优先遍历算法(又名交叉染色法)。
下面着重介绍下交叉染色法的定义与原理首先任意取出一个顶点进行染色,和该节点相邻的点有三种情况:1.如果节点没有染过色,就染上与它相反的颜色,推入队列,2.如果节点染过色且相反,忽视掉,3.如果节点染过色且与父节点相同,证明不是二分图,return二分图博客推荐交叉染色法博客推荐:交叉染色法判断二分图另外附上二分图的性质博客:二分图的一些性质1.KM算法初步KM算法全称是Kuhn-Munkras,是这两个人在1957年提出的,有趣的是,匈牙利算法是在1965年提出的。
?增广路径增广路径定义:若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M 的一条增广路径(举例来说,有A、B集合,增广路由A中一个点通向B中一个点,再由B中这个点通向A中一个点……交替进行)增广路径有如下特性:?1. 有奇数条边?2. 起点在二分图的X边,终点在二分图的Y边?3. 路径上的点一定是一个在X边,一个在Y边,交错出现。
?4. 整条路径上没有重复的点?5. 起点和终点都是目前还没有配对的点,其他的点都已经出现在匹配子图中?6. 路径上的所有第奇数条边都是目前还没有进入目前的匹配子图的边,而所有第偶数条边都已经进入目前的匹配子图。
奇数边比偶数边多一条边?7. 于是当我们把所有第奇数条边都加到匹配子图并把条偶数条边都删除,匹配数增加了1.例如下图,蓝色的是当前的匹配子图,红色表示未匹配的路径,目前只有边x0y0,然后通过x1找到了增广路径:x1y0-y0x0-x0y2?增广路径有两种寻径方法,一个是深搜,一个是宽搜。
图论课件-匈牙利算法与最优匹配算法
![图论课件-匈牙利算法与最优匹配算法](https://img.taocdn.com/s3/m/0eba090dbf23482fb4daa58da0116c175f0e1eeb.png)
x4
x5
(2) NGl (S) y2, y3 T
y1 y2 y3
y4
y5
(3) 取:y2 NGl (S ) T
G l=(X, Y)
y2为饱和顶点,y2x1 ∈M,于是: S x1, x4,T y2
(2) NGl (S) y2, y3 T
(3) 取:y3 NGl (S ) T
y3为饱和顶点,y3x3 ∈M,于是:S x1, x3, x4,T y2, y3
11
1
0.5 n 0
0.5
1 2 1.5 t1
0.5
00
1 0.8
0.6 0.4 x 0.2
偶图中寻找最大匹配算法:
设M是G=(X, Y)的初始匹配。
(1) 置S=Φ, T=Φ;
(2) 若X-S已经M饱和,停止;否则,设u是X-S中的一 非饱和顶点,置S=S∪{u}。
(3) 若N(S)=T,转(5);否则,设y ∈N(S)-T。
y2
x5
x4
x2
y4
y3
u
扎根 u 的M交错树H
情形2 H包含除u外的M非饱和点。
y2
x4
x2
y4
y3
u
扎根 u 的M交错树H
4
1
0.5 n 0
0.5
1 2 1.5 t1
0.5
00
1 0.8
0.6 0.4 x 0.2
对于情形1,令S=V(H)∩X, T=V(H)∩Y,显然: T N(S)
1) 若N(S)=T, 由于S - {u}中点与T中点配对,所以有: |T|=|S|-1, 于是有: |N(S)| = |S|-1< |S|.由Hall定理,G中不存 在完美匹配;
K M 算 法 详 解
![K M 算 法 详 解](https://img.taocdn.com/s3/m/2f576664f111f18582d05a44.png)
KM算法详解(例题为HDU2255 带权二分图的最优匹配):希望你在阅读此篇博客时,你已经学会了匈牙利算法,这样会对你更有帮助哦!!!!!对于KM算法自己的通俗理解与代码详解:注:KM算法:就是在匈牙利基础上加了权值的束缚!那么,为了达到权值和最大,或者最小,就不能简单的去算最多的边数。
步骤:(以HDU2255 例题为例)1.首先要找到所有居民愿意花钱最多的那个房子。
题目中用到lx,ly数组,是为了同时调节两个数组,使得权值和最大。
或者说当要松弛的时候使得本来最大的矛盾权值和尽可能的损失小一些来得到满足条件的最大权值和!2.(lx[x]+ly[y]-w[x][y]=0)条件下进行匈牙利算法。
lx[x]+ly[y]-w[x][y]这个条件十分巧妙:(算法精髓)1.即可以只让指定居民找到它愿意付最多钱的房子。
2.又可以在发生多居民抢一个房子时,用它来得到该居民到其它房子的松弛量!(即该居民到其它房子比到这个用钱最多的房子愿意花的钱数上差的值。
)那么我们就要把发生矛盾的居民到其它房子的松弛量的最小值求出来。
再用它去松弛,就可以让原本矛盾的最大权值和,损失最小而得到满足条件的最大权值和对于每个居民有4个基本问题:1.这个房子访问过没有?2.这个房子能不能满足他的条件3.这个房子是否被别人住了4.被别人住了能不能得到调配代码如下:#include iostream#includecstdio#includecstringusing namespace std;#define MAX 310#define INF 125#define clr(x) memset(x,0,sizeof(x))int w[MAX][MAX];int lx[MAX],ly[MAX]; -***lx[i]初始化为A集合中 i 点能到B集合某一点的最大权值, ly[i] 初始化0;***-int link[MAX];int slack[MAX];int visx[MAX],visy[MAX];bool find(int x)visx[x]=1; -****得到发生矛盾的居民集合****-for(int y=1;y=n;y++) -**这个居民,每个房子都去试一试!(找到就退出)**-if(visy[y]) -****一个房子不需要重复访问****-continue;int t=lx[x]+ly[y]-w[x][y];-****按这个标准去用-匈牙利算法***- if(t==0) -**t==0标志这个房子可以给这位居民**-visy[y]=1;if(link[y]==0||find(link[y])) -****这房子没人住或可以让住这个房子的人去找另外的房子住****-link[y]=x;return true; -**那么就可以让这位居民住进来**-else if(slack[y]t) -**否则这个房子不能给这位居民!**-slack[y]=t; -***就要找到这个房子要松弛多少才能够给这位居民***--***且当有多个居民都对这个房子有松弛量时,要找到最小的。
基于匈牙利算法评估路由算法中网络负载的方法
![基于匈牙利算法评估路由算法中网络负载的方法](https://img.taocdn.com/s3/m/05709ace524de518964b7dd2.png)
基于匈牙利算法评估路由算法中网络负载的方法作者:张方爽段新明来源:《软件工程》2018年第06期摘要:最坏情况的吞吐率是衡量路由算法性能的重要因素之一。
负载最重的地方是最坏情况吞吐率的体现,因此最坏情况的吞吐率在路由算法中很关键。
在此基础上本文提出了通过利用匈牙利算法来评估网络负载的方法并且通过实验仿真进行比较。
将匈牙利算法和穷举法运用到Oblivious路由中的O1TURN、VAL等算法中进行比较。
实验结果表明运用该方法与利用传统的穷举法相比,可以大大减少计算量、降低时间复杂度,实验结果证明了方法的可行性和有效性。
关键词:匈牙利算法;最坏情况吞吐率;Oblivious路由;穷举法中图分类号:TP393 文献标识码:A1 引言(Introduction)路由算法是决定网络性能重要因素之一,最坏情况的吞吐率是衡量路由算法的重要指标。
通过随机选择路由路径网络传输过程中故障节点绕道路由问题,以及自适应网络选择路由的路径问题,负载最重的地方是最坏情况吞吐率的体现,因此最坏情况的吞吐率在路由算法中很关键[1,2]。
本文通过利用匈牙利算法的思想计算网络吞吐率的负载。
利用Oblivious路由功能的线性,找到最坏情况的流量模式被视为二分图的最大权重匹配。
使用这种结构,问题通常在多项式时间内解决,快速产生确切的最坏情况结果。
使用最坏情况来确定特定系统的最坏情况吞吐。
William J.Dally等人提出将匈牙利算法运用到Oblivious路由中的DOR和ROMM中评估吞吐率[3],在此基础上本文引入扩展到Oblivious路由的O1TURN等算法中[1,4]。
2 相关知识(Related information)匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名。
匈牙利算法是基于Hall定理中充分性证明的思想,它是二分图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
3
4
例题1 Place the Robots(ZOJ) 模型二
把每个横向块看作X部的点,竖向 块看作Y部的点,若两个块有公共 的空地,则在它们之间连边。 于是,问题转化成这样的一个二 部图:
1 2 3 4 5
1 2 5 3 4
1 2
1 2 3 4
3
4
例题1 Place the Robots(ZOJ) 模型二
KM算法
对于任意的G和M,可行顶标都是存在的: l(x) = maxw(x,y) l(y) = 0 欲求完全二分图的最佳匹配,只要用匈牙利算法求 其相等子图的完备匹配;问题是当标号之后的Gl无 完备匹配时怎么办?1957年(居然比匈牙利算法 早???),Kuhn和Munkras给出了一个解决该问 题的有效算法,用逐次修改可行顶标l(v)的办法使对 应的相等子图之最大匹配逐次增广,最后出现完备 匹配。
匈牙利算法
程序清单: Function find(k:integer):integer; var st,sf,i,j,t:integer; queue,father:array[1..100] of integer; begin queue[1] := k; st := 1; sf := 1; fillchar(father,sizeof(father),0); repeat
KM算法
穷举的效率-n!,我们需要更加优秀的算法。 定理: 设M是一个带权完全二分图G的一个完备匹配,给 每个顶点一个可行顶标(第i个x顶点的可行标用lx[i] 表示,第j个y顶点的可行标用ly[j]表示),如果对所 有的边(i,j) in G,都有lx[i]+ly[j]>=w[i,j]成立(w[i,j]表示 边的权),且对所有的边(i,j) in M,都有lx[i]+ly[j]=w[i,j] 成立,则M是图G的一个最佳匹配。证明很容易。
匈牙利算法
由增广路的定义可以推出下述三个结论: 1-P的路径长度必定为奇数,第一条边和最 后一条边都不属于M。 2-P经过取反操作可以得到一个更大的匹配 M’。 3-M为G的最大匹配当且仅当不存在相对于 M的增广路径。
匈牙利算法
用增广路求最大匹配(称作匈牙利算法,匈牙 利数学家Edmonds于1965年提出) 算法轮廓: (1)置M为空 (2)找出一条增广路径P,通过取反操作获得 更大的匹配M’代替M (3)重复(2)操作直到找不出增广路径为止
例题1 Place the Robots(ZOJ1654) 问题描述
有一个N*M(N,M<=50)的棋盘, 棋盘的每一格是三种类型之一: 空地、草地、墙。机器人只能放 在空地上。在同一行或同一列的 两个机器人,若它们之间没有墙, 则它们可以互相攻击。问给定的 棋盘,最多可以放置多少个机器 人,使它们不能互相攻击。
匈牙利算法
for i:=1 to n do if (father[i]=0)and(a[queue[st],i]=1) then begin if match2[i]<>0 then begin inc(sf); queue[sf] := match2[i]; father[i] := queue[st]; end else
1 2 3 4 5
1 2 5 3 4
1
2
3
4
由于每条边表示一个空地,有冲 突的空地之间必有公共顶点,所 以问题转化为二部图的最大匹配 问题。
1 2
3
4
例题1 Place the Robots(ZOJ) 小结
比较前面的两个模型:模型一过于简单,没有给问 题的求解带来任何便利;模型二则充分抓住了问题的内 在联系,巧妙地建立了二部图模型。为什么会产生这种 截然不同的结果呢?其一是由于对问题分析的角度不同: 模型一以空地为点,模型二以空地为边;其二是由于对 原型中要素的选取有差异:模型一对要素的选取不充分, 模型二则保留了原型中“棋盘”这个重要的性质。由此 可见,对要素的选取,是图论建模中至关重要的一步。
Empty Grass Wall
例题1 Place the Robots(ZOJ) 模型一
在问题的原型中,草地,墙这些信 息不是我们所关心的,我们关心的 只是空地和空地之间的联系。因此, 我们很自然想到了下面这种简单的 模型: 以空地为顶点,有冲突的空地间连 边,我们可以得到右边的这个图: 于是,问题转化为求图的最大独立 集问题。
KM算法
修改方法如下: 先将一个未被匹配的顶点u(u in {x})做一次增广路, 记下哪些结点被访问那些结点没有被访问。求出 d=min{lx[i]+ly[j]-w[i,j]}其中i结点被访问,j结点没有 被访问。然后调整lx和ly:对于访问过的x顶点,将 它的可行标减去d,对于所有访问过的y顶点,将它 的可行标增加d。修改后的顶标仍是可行顶标,原 来的匹配M仍然存在,相等子图中至少出现了一条 不属于M的边,所以造成M的逐渐增广。
例题2 救护伤员(TOJ1148) 无情的海啸夺取了无数人的生命.很多的医疗 队被派往灾区拯救伤员.就在此时,医疗队突 然发现自己带的药品已经不够用了,只剩下了 N种。(1 < n <= 20),随着病人病情的发 展,每种药在每天能获得的效果是不一样的。 同时,每天病人只能服用一种药。也就是说, 这些药还够支持N天。现在,给出你每种药 在每天使用的效果,请你判断当每种药都用 完后所有药达到的效果之和最大可以是多少。
1 2 3 4
1 3 8 5 7 6 2 4
8 7 6 5
这是NP问题!
例题1 Place the Robots(ZOJ) 模型二
我们将每一行,每一列被墙隔开, 且包含空地的连续区域称作 “块”。显然,在一个块之中, 最多只能放一个机器人。我们把 这些块编上号。 1 2 2 5 1 3 4
同样,把竖直方向的块也编上号。
例题4 最小路径覆盖 一个不含圈的有向图G中,G的一个路径覆盖 是一个其结点不相交的路径集合P,图中的每 一个结点仅包含于P中的某一条路径。路径可 以从任意结点开始和结束,且长度也为任意 值,包括0。请你求任意一个不含圈的有向图 G的最小路径覆盖数。 理清一个关系:最小路径覆盖数=G的定点 数-最小路径覆盖中的边数
KM算法
上述算法的证明也很容易 Kuhn-Munkras算法流程: (1)初始化可行顶标的值 (2)用匈牙利算法寻找完备匹配 (3)若未找到完备匹配则修改可行顶标的值 (4)重复(2)(3)直到找到相等子图的完备匹配为 止
参考文献
王树禾《离散数学引论》 吴文虎 王建德《图论算法与程序设计》 刘汝佳 黄亮《算法艺术与信息学竞赛》 2002年冬令营论文-孙方成《偶图的算法及 应用》 2004年冬令营论文-黄源河《浅谈图论模型 的建立与应用》
匈牙利算法
begin j := queue[st]; while true do begin t := match1[j]; match1[j] := i; match2[i] := j; if t = 0 then break; i := t; j := father[t];
匈牙利算法
end; find := 1; exit; end; end; inc(st); until st>sf; find := 0; end;
1 2 3 4
1 3 8 5 7 6 2 4
8 7 6 5
例题1 Place the Robots(ZOJ) 模型一
在问题的原型中,草地,墙这些信 息不是我们所关心的,我们关心的 只是空地和空地之间的联系。因此, 我们很自然想到了下面这种简单的 模型: 以空地为顶点,有冲突的空地间连 边,我们可以得到右边的这个图:
匈牙利算法
求最大匹配的一种显而易见的算法是:先找出全部 匹配,然后保留匹配数最多的。但是这个算法的复 杂度为边数的指数级函数。因此,需要寻求一种更 加高效的算法。 增广路的定义(也称增广轨或交错轨): 若P是图G中一条连通两个未匹配顶点的路径,并且 属M的边和不属M的边(即已匹配和待匹配的边)在P 上交替出现,则称P为相对于M的一条增广路径。
匈牙利算法
在主程序中调用下面的程序即可得出最大匹 配数。 Bmatch := 0; For I:=1 to n do Bmatch := Bmatch + find(i); Writeln(Bmatch); 一个关于二分图的性质: 最大匹配数+最大独立集=X+Y
最佳匹配
如果边上带权的话,找出权和最大的匹配叫 做求最佳匹配。 实际模型:某公司有职员x1,x2,…,xn,他们去 做工作y1,y2,…,yn,每个职员做各项工作的效 益未必一致,需要制定一个分工方案,使得 人尽其才,让公司获得的总效益最大。 数学模型:G是加权完全二分图,求总权值 最大的完备匹配。
例题 最小路径覆盖
试想我们应该使得最小路径覆盖中的边数尽量多, 但是又不能让两条边在同一个顶点相交。 拆点:将每一个顶点i拆成两个顶点Xi和Yi。然后根 据原图中边的信息,从X部往Y部引边。所有边的方 向都是由X部到Y部。
例题4 最小路径覆盖 因此,所转化出的二分图的最大匹配数则是 原图G中最小路径覆盖上的边数。因此由最 小路径覆盖数=原图G的顶点数-二分图的 最大匹配数便可以得解。
例题3 打猎 猎人要在n*n的格子里打鸟,他可以在某一行 中打一枪,这样此行中的所有鸟都被打掉, 也可以在某一列中打,这样此列中的所有鸟 都打掉。问至少打几枪,才能打光所有的鸟? 建图:二分图的X部为每一行,Y部为每一列, 如果(i,j)有一只鸟,那么连接X部的i与Y部的j。 该二分图的最大匹配数则是最少要打的枪数。
二分图匹配
匈牙利算法和KM算法简介
二分图的概念
二分图又称作二部图,是图论中的一种特殊 模型。 设G=(V,{R})是一个无向图。如顶点集V可分 割为两个互不相交的子集,并且图中每条边 依附的两个顶点都分属两个不同的子集。则 1 2 3 4 5 称图G为二分图。