二分图匹配(匈牙利算法)

合集下载

匈牙利算法解决二分图最大匹配

匈牙利算法解决二分图最大匹配

匈⽛利算法解决⼆分图最⼤匹配预备知识 匈⽛利算法是由匈⽛利数学家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个剩⼥,每个⼈都可能对多名异性有好感(惊讶,-_-||暂时不考虑特殊的性取向) 如果⼀对男⼥互有好感,那么你就可以把这⼀对撮合在⼀起,现在让我们⽆视掉所有的单相思(好忧伤的感觉,快哭了),你拥有的⼤概就是下⾯这样⼀张关系图,每⼀条连线都表⽰互有好感。

二分图匹配(匈牙利算法)

二分图匹配(匈牙利算法)

设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; //路径取反操作。

二分图匹配--匈牙利算法

二分图匹配--匈牙利算法

⼆分图匹配--匈⽛利算法⼆分图匹配--匈⽛利算法⼆分图匹配匈⽛利算法基本定义:⼆分图 —— 对于⽆向图G=(V,E),如果存在⼀个划分使V中的顶点分为两个互不相交的⼦集,且每个⼦集中任意两点间不存在边 ϵ∈E,则称图G为⼀个⼆分图。

⼆分图的充要条件是,G⾄少有两个顶点,且所有回路长度为偶数。

匹配 —— 边的集合,其中任意两条边都不存在公共顶点。

匹配边即是匹配中的元素,匹配点是匹配边的顶点,同样⾮匹配边,⾮匹配点相反定义。

最⼤匹配——在图的所有匹配中,包含最多边的匹配成为最⼤匹配 完美匹配——如果在⼀个匹配中所有的点都是匹配点,那么该匹配称为完美匹配。

附注:所有的完美匹配都是最⼤匹配,最⼤匹配不⼀定是完美匹配。

假设完美匹配不是最⼤匹配,那么最⼤匹配⼀定存在不属于完美匹配中的边,⽽图的所有顶点都在完美匹配中,不可能找到更多的边,所以假设不成⽴,及完美匹配⼀定是最⼤匹配。

交替路——从⼀个未匹配点出发,依次经过⾮匹配边,匹配边,⾮匹配边…形成的路径称为交替路,交替路不会形成环。

增⼴路——起点和终点都是未匹配点的交替路。

因为交替路是⾮匹配边、匹配边交替出现的,⽽增⼴路两端节点都是⾮匹配点,所以增⼴路⼀定有奇数条边。

⽽且增⼴路中的节点(除去两端节点)都是匹配点,所属的匹配边都在增⼴路径上,没有其他相连的匹配边,因此如果把增⼴路径中的匹配边和⾮匹配边的“⾝份”交换,就可以获得⼀个更⼤的匹配(该过程称为改进匹配)。

⽰例图Fig1_09_09.JPG注释:Fig3是⼀个⼆分图G=(V,E),V={1,2,3,4,5,6,7,8},E={(1,7),(1,5),(2,6),(3,5),(3,8),(4,5),(4,6)},该图可以重绘成Fig4,V可分成两个⼦集V={V1,V2},V1={1,2,3,4},V2={5,6,7,8}。

Fig4中的红⾊边集合就是⼀个匹配{(1,5),(4,6),(3,8)}Fig2中是最⼤匹配Fig1中红⾊边集合是完美匹配Fig1中交替路举例(4-6-2-7-1-5)Fig4中增⼴路(2-6-4-5-1-7)匈⽛利树匈⽛利树中从根节点到叶节点的路径均是交替路,且匈⽛利树的叶节点都是匹配点。

匈牙利匹配算法的原理

匈牙利匹配算法的原理

匈牙利匹配算法的原理匈牙利匹配算法(也被称为二分图匹配算法或者Kuhn-Munkres算法)是用于解决二分图最大匹配问题的经典算法。

该算法由匈牙利数学家Dénes Kőnig于1931年提出,并由James Munkres在1957年进行改进。

该算法的时间复杂度为O(V^3),其中V是图的顶点数。

匹配问题定义:给定一个二分图G=(X,Y,E),X和Y分别代表两个不相交的顶点集合,E表示连接X和Y的边集合。

图中的匹配是指一个边的集合M,其中任意两条边没有公共的顶点。

匹配的相关概念:1.可增广路径:在一个匹配中找到一条没有被占用的边,通过这条边可以将匹配中的边个数增加一个,即将不在匹配中的边添加进去。

2. 增广路径:一个可增广路径是一个交替序列P=v0e1v1e2v2...ekvk,其中v0属于X且不在匹配中,v1v2...vk属于Y且在匹配中,e1e2...ek在原图中的边。

3.增广轨:一个交替序列形如V0E1V1E2...EkVk,其中V0属于X且不在匹配中,V1V2...Vk属于Y且在匹配中,E1E2...Ek在原图中的边。

增广轨是一条路径的特例,它是一条从X到Y的交替序列。

1.初始时,所有的边都不在匹配中。

2.在X中选择一个点v0,如果v0已经在匹配中,则找到与v0相连的在Y中的顶点v1、如果v1不在匹配中,则(v0,v1)是可增广路径的第一条边。

3. 如果v1在匹配中,则找到与v1相连的在X中的顶点v2,判断v2是否在匹配中。

依此类推,直到找到一个不在匹配中的点vn。

4.此时,如果n是奇数,则(n-1)条边在匹配中,这意味着我们找到了一条增广路径。

如果n是偶数,则(n-1)条边在匹配中,需要进行进一步的处理。

5.如果n是偶数,则将匹配中的边和非匹配中的边进行颠倒,得到一个新的匹配。

6.对于颠倒后的匹配,我们再次从第2步开始,继续寻找增广路径。

7.重复步骤2到步骤6,直到找不到可增广路径为止,此时我们得到了最大匹配。

二分图的最大匹配—匈牙利算法

二分图的最大匹配—匈牙利算法

⼆分图的最⼤匹配—匈⽛利算法【基本概念】:⼆分图:⼆分图⼆分图⼜称作⼆部图,是图论中的⼀种特殊模型。

设G=(V,E)是⼀个⽆向图,如果顶点V可分割为两个互不相交的⼦集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为⼀个⼆分图。

⽆向图G为⼆分图的充分必要条件是,G⾄少有两个顶点,且其所有回路的长度均为偶数。

最⼤匹配最⼤匹配:给定⼀个⼆分图G,在G的⼀个⼦图M中,M的边集中的任意两条边都不依附于同⼀个顶点,则称M是⼀个匹配. 选择这样的边数最⼤的⼦集称为图的最⼤匹配问题,如果⼀个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配.最⼩覆盖:最⼩覆盖要求⽤最少的点(X集合或Y集合的都⾏)让每条边都⾄少和其中⼀个点关联。

可以证明:最少的点(即覆盖数)=最⼤匹配数最⼩路径覆盖:⽤尽量少的不相交简单路径覆盖有向⽆环图G的所有结点。

解决此类问题可以建⽴⼀个⼆分图模型。

把所有顶点i拆成两个:X结点集中的i 和Y结点集中的i',如果有边i->j,则在⼆分图中引⼊边i->j',设⼆分图最⼤匹配为m,则结果就是n-m。

增⼴路(增⼴轨):(增⼴轨):增⼴路若P是图G中⼀条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的⼀条增⼴路径(举例来说,有A、B集合,增⼴路由A中⼀个点通向B中⼀个点,再由B中这个点通向A中⼀个点……交替进⾏)。

增⼴路径的性质:1 有奇数条边。

2 起点在⼆分图的左半边,终点在右半边。

3 路径上的点⼀定是⼀个在左半边,⼀个在右半边,交替出现。

(其实⼆分图的性质就决定了这⼀点,因为⼆分图同⼀边的点之间没有边相连,不要忘记哦。

)4 整条路径上没有重复的点。

5 起点和终点都是⽬前还没有配对的点,⽽其它所有点都是已经配好对的。

最大二分图匹配(匈牙利算法)

最大二分图匹配(匈牙利算法)

最大二分图匹配(匈牙利算法)二分图指的是这样一种图:其所有的顶点分成两个集合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.匈牙利算法在实际应用中可能存在数值稳定性问题,即在计算过程中可能出现精度误差。

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

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

用匈牙利算法求二分图的最大匹配二分图的最大匹配有两种求法,第一种是最大流;第二种就是匈牙利算法。

这个算法说白了就是最大流的算法,但是它跟据二分图匹配这个问题的特点,把最大流算法做了简化,提高了效率。

最大流算法的核心问题就是找增广路径(augment path)。

匈牙利算法也不例外,它的基本模式就是:初始时最大匹配M为空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个。

匈牙利算法流程

匈牙利算法流程

匈牙利算法流程匈牙利算法是一种经典的图论算法,用于解决二分图的最大匹配问题,其流程简洁而高效。

下面将以人类的视角来叙述匈牙利算法的流程。

我们假设有一个二分图,其中左边有一组顶点,右边有另一组顶点。

我们的目标是找到一个最大的匹配,即找到左边的每个顶点与右边的某个顶点之间的边,使得每个右边的顶点最多与一个左边的顶点相连。

开始时,我们将所有的边标记为未匹配状态。

然后,我们从左边的第一个顶点开始,尝试寻找一个未匹配的右边的顶点。

如果找到了,我们将这条边标记为匹配状态,并继续寻找下一个左边的顶点。

如果没有找到,我们就需要进行增广路径的寻找。

为了寻找增广路径,我们从未匹配的左边顶点开始,沿着它的边逐个访问右边的顶点。

如果当前的右边顶点已经匹配了,我们就尝试寻找与这个右边顶点相匹配的左边顶点,然后再以这个左边顶点为起点,继续递归地寻找下一个右边顶点。

如果找到了增广路径,我们就可以通过交替匹配和取消匹配来增加匹配数目。

为了实现这个过程,我们需要用一个数组来保存每个左边顶点的匹配状态,另一个数组来保存每个右边顶点的匹配状态。

同时,我们还需要一个标记数组来记录每个左边顶点是否已经访问过。

通过深度优先搜索的方式,我们可以找到增广路径并更新匹配状态。

当所有的左边顶点都被访问过时,我们就找到了一个最大的匹配。

此时,我们可以输出匹配数目,或者根据需要输出具体的匹配方案。

总结一下,匈牙利算法通过不断寻找增广路径来增加匹配数目,直到无法找到增广路径为止。

它的核心思想是通过深度优先搜索来寻找增广路径,以达到最大匹配的目标。

这个算法简单而高效,被广泛应用于实际问题的求解中。

二分图(匈牙利,KM算法详解)

二分图(匈牙利,KM算法详解)
3,假如我们在1,2步过程中找到一条增广路, 那么修改各自 对应的匹配点,转步骤4,若无增广路, 则退出.
4,匹配数+1;
最小点覆盖
最小覆盖: 最小覆盖要求用最少的点(X集 合或Y集合的都行)让每条边都至少和其中一 个点关联。可以证明:最少的点(即覆盖数) =最大匹配数 M
简单的证明如下:
1
4
1
4
2
5 把图中红色线去掉
2
5
蓝色线加上
3
6
3
6
1
4
更改各自的匹配点
找到一个更好的匹配 2
5
3
6
总结
所以流程就是:
1,对于一个未匹配的节点u,寻找它的每条边,如果它的边上 的另一个节点v还没匹配则表明找到了一个匹配,直接转步 骤4;
2,假如节点u它边上的另一个节点v已经匹配,那么就转向跟 v匹配的节点,假设是w,然后再对w重复1,2的步骤,即寻找增 广路.
现在我们假设要求的是最大距离.那么就是求最大权 匹配. 下面我们先介绍一下KM算法
KM算法
基本概念:可行顶标和相等子图
可行顶标:L是一个关于结点的函数,L(x)是顶点x对应 的顶标值。可行顶标对于图中的每条边(x,y)都有 L(x)+L(y)>=w(x,y)
相等子图:只包含L(x)+L(y)=w(x,y)的边的子图
KM算法
定理:如果一个相等子图中包含完备匹配,那 么这个匹配就是最优匹配
证明:由于在算法过程一直保持顶标的可行性, 所以任意一个匹配的权值和肯定小于等于所有 结点的顶标之和,则相等子图中的完备匹配肯 定是最优匹配
KM算法
算法流程 设顶点Xi的顶标为a[i],顶点Yi的顶标为b[i] ⅰ.初始时,a[i]为与Xi相关联的边的最大权值,

匈牙利算法详解

匈牙利算法详解

匈牙利算法详解
匈牙利算法是一种解决二分图最大匹配问题的经典算法,也叫做增广路算法。

它的基本思想是从左侧一端开始,依次匹配左侧点,直到无法添加匹配为止。

在匹配过程中,每次都通过BFS 寻找增广路径,即可以让已有的匹配变得更优或添加新的匹配。

增广路的长度必须为奇数,因为必须从未匹配的左侧点开始,交替经过已匹配的右侧点和未匹配的左侧点,最后再到达未匹配的右侧点。

当没有找到增广路径时,匹配结束。

匈牙利算法的具体实现可以使用DFS 或BFS,这里以BFS 为例。

算法步骤如下:
1. 从左侧一个未匹配的点开始,依次找增广路径。

如果找到,就将路径上的匹配状态翻转(即已匹配变未匹配,未匹配变已匹配),并继续找增广路径;如果找不到,就说明已经完成匹配。

2. 使用BFS 寻找增广路径。

从左侧的某个未匹配点开始,依次搜索路径中未匹配的右侧点。

如果找到右侧未匹配点,则说明找到了增广路径;否则,将已搜过的左侧点打上标记,以免重复搜索。

如果找到增广路径,就将路径的左侧和右侧点的匹配状态翻转。

3. 重复步骤1 和2,直到找不到增广路径为止。

匈牙利算法的时间复杂度为O(VE),其中V 和E 分别为二分图中的左侧点数和右侧点数。

实际运行效率很高,可以处理百万级别的数据。

匈牙利算法 描述

匈牙利算法 描述

匈牙利算法描述匈牙利算法是图论中一种用于解决二分图匹配问题的算法。

它首次由匈牙利数学家Denzel匈牙利在1955年发表,因而得名。

匈牙利算法属于图匹配算法的范畴,在实际应用中有着很强的效率和准确性。

本文将介绍匈牙利算法的原理、实现方法和应用领域等相关内容。

一、匈牙利算法原理匈牙利算法是解决二分图最大匹配问题的经典算法之一。

在二分图中,匈牙利算法的目标是寻找图中的最大匹配,即尽可能多地找到满足匹配条件的边,也就是找到尽可能多的配对节点。

在匈牙利算法中,主要使用了增广路的概念,通过不断地寻找增广路,来不断地扩展匹配。

具体而言,匈牙利算法的核心思想是利用增广路径寻找最大匹配。

在每一次匹配的过程中,首先选择一个未匹配的节点,然后通过交替路径寻找增广路径,直到无法找到增广路径为止。

当无法找到增广路径时,说明找到了最大匹配。

增广路径指的是一条由未匹配的节点和匹配节点交替构成的路径,其中未匹配节点为起点和终点。

通过不断地寻找增广路径,可以逐步扩展匹配。

在匈牙利算法中,为了记录节点的匹配状态和寻找增广路径,通常使用匈牙利标号和匈牙利交错路的方式。

匈牙利标号是为每个节点标记一个代表节点匹配状态的值,而匈牙利交错路则是一种用于寻找增广路径的方法。

借助这些工具,匈牙利算法可以高效地解决最大匹配问题。

二、匈牙利算法实现方法匈牙利算法的实现方法较为复杂,需要结合图论和图匹配的相关知识。

在实际应用中,匈牙利算法通常通过编程实现,以解决特定的二分图匹配问题。

下面简要介绍匈牙利算法的一般实现方法。

1. 初始化匈牙利标号:首先对图中的所有未匹配节点进行初始化标号,即给它们赋予一个初始的匈牙利标号。

2. 寻找增广路径:选择一个未匹配的节点作为起点,通过交替路径和增广路的方法寻找增广路径。

在寻找增广路径的过程中,要根据节点的匈牙利标号来选择下一个节点,从而找到满足匹配条件的路径。

3. 匹配节点:如果成功找到一条增广路径,就可以将路径中的节点进行匹配,即将原来未匹配的节点与匹配节点进行匹配。

匈牙利规则

匈牙利规则

匈牙利规则
"匈牙利规则"通常指的是在图论中解决二分图匹配问题的一个算法,也称为匈牙利算法或Kőnig算法。

这个算法由匈牙利数学家Dénes Kőnig在1925年提出,用于寻找二分图中的最大匹配。

二分图是一种特殊的图,其顶点可以分成两个不相交的集合,并且图中的每条边都连接这两个集合中的一个顶点。

匈牙利算法的步骤如下:
1. 选择一个未匹配的顶点u from U,U是图中的一半顶点集合。

2. 对于u的每个邻接顶点v from V,如果v尚未匹配,则将其标记为未使用的。

3. 如果u的所有邻接顶点都已被使用,则算法结束,当前匹配是最大匹配。

4. 如果存在一个未使用的顶点v,则将v与u匹配,并转步骤1。

5. 如果u的所有邻接顶点都已被使用,但不是都与u匹配,选择一个与u匹配的顶点w,并找出通过u和w形成的未使用的环。

在这个环上,交替取消匹配的边,直到找到一个未匹配的顶点x。

6. 选择x的一个未使用的邻接顶点y,并取消u与y的匹配。

7. 匹配x和y,并转步骤1。

这个算法可以找到二分图中最大的匹配,并且在实现上相对高效。

它在理论计算机科学和组合优化中有着广泛的应用,例如在网络流问题、调度问题以及一些经济和生物信息学问题中。

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

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

一、用匈牙利算法求二分图(二部图,偶图的最大匹配算法中的几个术语说明: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,并且这个图中的每一条边都连接一种类型的点到另一种类型的点。

比如下图就是一个二分图:![image.png](attachment:image.png)红色的节点集合A为{1,2,3,4},绿色的节点集合B为{5,6,7},这个二分图中的边连接着节点集合A和B中的节点。

这个二分图可以用一个邻接矩阵或邻接表来表示。

二、匈牙利算法的思路匈牙利算法就是基于二分图的特点,采用增广路的思想,在该图中寻找从某个未匹配点出发,能够增加一条匹配边的路径。

具体找到的这条路径称之为增广路。

通过不断地寻找增广路,可以找到最大匹配。

1. 初始化:所有的节点都没有匹配,无数个节点都是自由节点。

初始时可以假设所有的匹配都为空。

2. 选择自由节点开始搜索:从未匹配的节点开始遍历,如果发现了一个未被检查过的自由节点,就从这个节点开始进行深度优先搜索(DFS)。

3. 搜索增广路:对于任意一个节点,如果它还没有被匹配,那么就找到和它有边连接的节点。

如果该节点没有匹配,那么就找到了一条增广路(因为这条路的两个端点都是自由节点),此时退出DFS并返回true。

否则,如果该节点已经有匹配了,就递归地尝试去找该节点的匹配节点。

这里需要注意的是,一旦某个节点尝试找到了增广路,那么后续的节点都不需要再进行探索。

4. 匹配:如果找到了增广路,就从路径上交替匹配边,这些边将变成匹配边。

如果没有找到增广路,退出DFS并返回false。

1. 如何判断节点是否为自由节点?在初始时,所有的节点都是自由节点,每次匹配成功后,匹配边的两个点都会变成非自由节点。

重点是如何判断一个非自由节点是否已经匹配。

常用的方法是使用match[i]来表示i节点已经匹配的节点编号。

匈牙利算法原理

匈牙利算法原理

匈牙利算法原理
匈牙利算法是一种用于解决二分图最大匹配问题的算法。

在二分图中,将图中的节点分为两个集合,分别为左侧节点集合和右侧节点集合,且左侧节点集合中的节点与右侧节点集合中的节点之间不存在边,只有左侧节点集合中的节点与右侧节点集合中的节点之间存在边。

二分图最大匹配问题就是找到一种最优的匹配方式,使得左侧节点集合中的每个节点都与右侧节点集合中的一个节点匹配。

匈牙利算法的基本思想是:从左侧节点集合中的每个节点开始,依次寻找与其匹配的右侧节点,如果找到了一个右侧节点,就将该右侧节点与左侧节点匹配,并继续寻找下一个左侧节点的匹配。

如果找不到一个右侧节点与该左侧节点匹配,就回溯到上一个左侧节点,并尝试匹配其他右侧节点,直到找到一个能够匹配的右侧节点或者所有的右侧节点都已经尝试过。

匈牙利算法的实现过程可以分为以下几个步骤:
1. 初始化:将所有的左侧节点都标记为未匹配状态。

2. 从左侧节点集合中的每个未匹配节点开始,依次进行匹配。

3. 对于每个未匹配节点,寻找与其相连的所有右侧节点,并尝试将其与该左侧节点匹配。

4. 如果找到了一个未匹配的右侧节点,就将该右侧节点与该左侧节点匹配,并将该左侧节点标记为已匹配状态。

5. 如果找不到一个未匹配的右侧节点与该左侧节点匹配,就回溯到上一个左侧节点,并尝试匹配其他右侧节点。

6. 如果所有的左侧节点都已经匹配完成,就得到了一个最大匹配。

7. 如果还存在未匹配的左侧节点,就说明无法找到一个最大匹配。

匈牙利算法的时间复杂度为O(n^3),其中n为节点的数量。

虽然时间复杂度比较高,但是匈牙利算法在实际应用中表现良好,可以处理大规模的二分图最大匹配问题。

二分图匹配算法(最大流匈牙利)

二分图匹配算法(最大流匈牙利)

⼆分图匹配算法(最⼤流匈⽛利)⼆分图匹配相关概念⽆向⼆分图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%。

km(kuhn-munkres)算法的具体表达

km(kuhn-munkres)算法的具体表达

km(kuhn-munkres)算法的具体表达KM算法,即Kuhn-Munkres算法(又称为匈牙利算法),是一种用于求解二分图最大权匹配问题的经典算法。

它由Eugene L. Lawler于1960年首次提出,后来由James Munkres在1957年独立发表,因此常称为Kuhn-Munkres算法。

二分图最大权匹配问题是指给定一个带权二分图,要求在图中选取权重之和最大的边集合,使得任意两条边不属于同一个顶点。

其中,带权二分图是指图的每条边都带有一个非负权重。

KM算法使用了两个关键的概念:交错树和相等子图。

交错树是指一个T=(S,P)的有向树,其中S是原二分图的所有顶点的集合,P是树中的边集合。

相等子图是指原二分图的一个子图,其中T中所有入树边的权重之和等于所有出树边的权重之和。

KM算法具体的步骤如下:1.初始化:将图中所有边的权重初始化为0,构建了一个初始的交错树T=(X,Y)(其中X,Y分别表示两个顶点集合)。

2.判断相等子图:对于T中的每个顶点x,如果存在一条满足lx+ly=W(其中lx是x在T中所有入树边的权重之和,ly是x在T中所有出树边的权重之和,W是x在原图G中的权重),则把x加入到相等子图中。

3.寻找未匹配节点:在相等子图中寻找未匹配节点,并标记为未父节点。

4.寻找增广路:如果存在未匹配节点,则从中选择一个起始节点,寻找一条与之交替出现的边构成的路径,使路径的最后一个边是一条与未匹配节点关联的边。

这样的路径称为增广路。

5.修改标号:对于相等子图中的每个顶点x,从已匹配节点中选择一个与之关联的顶点y,并计算d=min(lx+ly-w)(其中w是x和y之间的边的权重),为了使增广路更优,将T中所有x节点的入树边的权重减去d,将T中所有y节点的出树边的权重加上d。

6.更新交错树:将增广路中的所有边和T中的所有非树边进行调整,得到新的交错树。

7.重复步骤3-6,直到没有未匹配节点为止。

匈牙利匹配算法步骤

匈牙利匹配算法步骤

匈牙利匹配算法步骤匈牙利匹配算法是一种求解二分图最大匹配问题的高效算法。

它由匈牙利数学家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是图中顶点的数量。

而在实际情况中,由于可以使用各种优化技巧,例如使用数据结构来加速查找增广路径的过程,所以通常情况下算法的运行时间会远小于理论上的最坏情况。

此外,匈牙利匹配算法还有很好的可扩展性。

它可以很容易地推广到一些更复杂的问题,例如带权重的最大匹配问题、多对多匹配问题等。

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

KM算法
对于任意的G和M,可行顶标都是存在的: l(x) = maxw(x,y) l(y) = 0 欲求完全二分图的最佳匹配,只要用匈牙利算法求 其相等子图的完备匹配;问题是当标号之后的Gl无 完备匹配时怎么办?1957年(居然比匈牙利算法 早???),Kuhn和Munkras给出了一个解决该问 题的有效算法,用逐次修改可行顶标l(v)的办法使对 应的相等子图之最大匹配逐次增广,最后出现完备 匹配.
例题3 打猎 猎人要在n*n的格子里打鸟,他可以在某一行 中打一枪,这样此行中的所有鸟都被打掉, 也可以在某一列中打,这样此列中的所有鸟 都打掉.问至少打几枪,才能打光所有的鸟? 建图:二分图的X部为每一行,Y部为每一列, 如果(i,j)有一只鸟,那么连接X部的i与Y部的j. 该二分图的最大匹配数则是最少要打的枪数.
1 2 3 4 5
1 2 5 3 4
1
2
3
4
由于每条边表示一个空地,有冲 突的空地之间必有公共顶点,所 以问题转化为二部图的最大匹配 问题.
1 2Leabharlann 34例题1 Place the Robots(ZOJ) 小结
比较前面的两个模型:模型一过于简单,没有给问 题的求解带来任何便利;模型二则充分抓住了问题的内 在联系,巧妙地建立了二部图模型.为什么会产生这种 截然不同的结果呢?其一是由于对问题分析的角度不同: 模型一以空地为点,模型二以空地为边;其二是由于对 原型中要素的选取有差异:模型一对要素的选取不充分, 模型二则保留了原型中"棋盘"这个重要的性质.由此 可见,对要素的选取,是图论建模中至关重要的一步.
例题4 最小路径覆盖 一个不含圈的有向图G中,G的一个路径覆盖 是一个其结点不相交的路径集合P,图中的每 一个结点仅包含于P中的某一条路径.路径可 以从任意结点开始和结束,且长度也为任意 值,包括0.请你求任意一个不含圈的有向图 G的最小路径覆盖数. 理清一个关系:最小路径覆盖数=G的定点 数-最小路径覆盖中的边数
KM算法
上述算法的证明也很容易 Kuhn-Munkras算法流程: (1)初始化可行顶标的值 (2)用匈牙利算法寻找完备匹配 (3)若未找到完备匹配则修改可行顶标的值 (4)重复(2)(3)直到找到相等子图的完备匹配为 止
参考文献
王树禾《离散数学引论》 吴文虎 王建德《图论算法与程序设计》 刘汝佳 黄亮《算法艺术与信息学竞赛》 2002年冬令营论文-孙方成《偶图的算法及 应用》 2004年冬令营论文-黄源河《浅谈图论模型 的建立与应用》
1 2 3 4
1 3 8 5 7 6 2 4
8 7 6 5
例题1 Place the Robots(ZOJ) 模型一
在问题的原型中,草地,墙这些信 息不是我们所关心的,我们关心的 只是空地和空地之间的联系.因此, 我们很自然想到了下面这种简单的 模型: 以空地为顶点,有冲突的空地间连 边,我们可以得到右边的这个图:
匈牙利算法
在主程序中调用下面的程序即可得出最大匹 配数. Bmatch := 0; For I:=1 to n do Bmatch := Bmatch + find(i); Writeln(Bmatch); 一个关于二分图的性质: 最大匹配数+最大独立集=X+Y
最佳匹配
如果边上带权的话,找出权和最大的匹配叫 做求最佳匹配. 实际模型:某公司有职员x1,x2,…,xn,他们去 做工作y1,y2,…,yn,每个职员做各项工作的效 益未必一致,需要制定一个分工方案,使得 人尽其才,让公司获得的总效益最大. 数学模型:G是加权完全二分图,求总权值 最大的完备匹配.

匈牙利算法
程序清单: 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
匈牙利算法
求最大匹配的一种显而易见的算法是:先找出全部 匹配,然后保留匹配数最多的.但是这个算法的复 杂度为边数的指数级函数.因此,需要寻求一种更 加高效的算法. 增广路的定义(也称增广轨或交错轨): 若P是图G中一条连通两个未匹配顶点的路径,并且 属M的边和不属M的边(即已匹配和待匹配的边)在P 上交替出现,则称P为相对于M的一条增广路径.
例题4 最小路径覆盖
试想我们应该使得最小路径覆盖中的边数尽量多, 但是又不能让两条边在同一个顶点相交. 拆点:将每一个顶点i拆成两个顶点Xi和Yi.然后根 据原图中边的信息,从X部往Y部引边.所有边的方 向都是由X部到Y部.
例题4 最小路径覆盖 因此,所转化出的二分图的最大匹配数则是 原图G中最小路径覆盖上的边数.因此由最 小路径覆盖数=原图G的顶点数-二分图的 最大匹配数便可以得解.
匈牙利算法
由增广路的定义可以推出下述三个结论: 1-P的路径长度必定为奇数,第一条边和最 后一条边都不属于M. 2-P经过取反操作可以得到一个更大的匹配 M'. 3-M为G的最大匹配当且仅当不存在相对于 M的增广路径.
匈牙利算法
用增广路求最大匹配(称作匈牙利算法,匈牙 利数学家Edmonds于1965年提出) 算法轮廓: (1)置M为空 (2)找出一条增广路径P,通过取反操作获得 更大的匹配M'代替M (3)重复(2)操作直到找不出增广路径为止
Empty Grass Wall
例题1 Place the Robots(ZOJ) 模型一
在问题的原型中,草地,墙这些信 息不是我们所关心的,我们关心的 只是空地和空地之间的联系.因此, 我们很自然想到了下面这种简单的 模型: 以空地为顶点,有冲突的空地间连 边,我们可以得到右边的这个图: 于是,问题转化为求图的最大独立 集问题.
匈牙利算法
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
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的逐渐增广.
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
同样,把竖直方向的块也编上号.
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的一个最佳匹配.证明很容易.
例题2 救护伤员(TOJ1148) 无情的海啸夺取了无数人的生命.很多的医疗 队被派往灾区拯救伤员.就在此时,医疗队突 然发现自己带的药品已经不够用了,只剩下了 N种.(1 < n <= 20),随着病人病情的发 展,每种药在每天能获得的效果是不一样的. 同时,每天病人只能服用一种药.也就是说, 这些药还够支持N天.现在,给出你每种药 在每天使用的效果,请你判断当每种药都用 完后所有药达到的效果之和最大可以是多少.
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) 模型二
例题1 Place the Robots(ZOJ1654) 问题描述
有一个N*M(N,M<=50)的棋盘, 棋盘的每一格是三种类型之一: 空地,草地,墙.机器人只能放 在空地上.在同一行或同一列的 两个机器人,若它们之间没有墙, 则它们可以互相攻击.问给定的 棋盘,最多可以放置多少个机器 人,使它们不能互相攻击.
匈牙利算法
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;
二分图匹配
匈牙利算法和KM算法简介
二分图的概念
二分图又称作二部图,是图论中的一种特殊 模型. 设G=(V,{R})是一个无向图.如顶点集V可分 割为两个互不相交的子集,并且图中每条边 依附的两个顶点都分属两个不同的子集.则 1 2 3 4 5 称图G为二分图.
相关文档
最新文档