二分图完全匹配算法之匈牙利算法
最近在参加了一个小项目,里面用到二分图匹配算法,因为之前并没有接触过相关算法,于是找到一些博客进行了一番学习,但学习之后,发现部分博客或多或少存在一些另我疑惑的地方,于是,我打算写此博客以巩固对算法的理解。
一、二分图基本概念
二分图(Bipartite graph)又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
通俗一点,二分图是一类特殊的图,它可以被划分为两个部分,每个部分内的点互不相连。
如下图所示,可以将【2】【4】
结点视为一个集合,【1】【3】【5】【6】
结点视为一个集合,集合内部的结点互不相连,因此该图为一个二分图。
重要定理:G为二分图的充要条件是G中的每一个圈的长度都是偶数。
二、二分图匹配相关概念
1、什么是匹配?
注意,本文只讨论二分图的最大匹配,不讨论最优匹配。
给定一个二分图G=(V,E),在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配;具有边数量最多的匹配称为最大匹配;若|V|=2|M|,则称M为完美匹配。
如下所示为一个二分图的完美匹配:
二分图完美匹配一定是最大匹配,最大匹配不一定是完美匹配。
2、什么是交替路与增广路?
交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路。
增广路(Augmenting Path):从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发点不算),则这条【交替路】称为增广路。
增广路的三个性质:
- M为G的最大匹配当且仅当不存在M的增广路径。
- 增广路P的路径长度必定为奇数,第一条边和最后一条边都不属于M,不匹配的边比匹配的边多一。
- 不断寻找增广路可以得到一个更大的匹配M’,直到找不到更多的增广路。
增广路的这三个性质可以用来寻找匹配,在接下来会说明。
如下图所示:
路径2
->A
->1
->B
为一条交替路,因为出发点2
和途径点B
均为未匹配点,因此该路径也为增广路。
三、匈牙利算法
1、基本概念
匈牙利算法的核心就是寻找增广路。具体而言,匈牙利算法从二分图中没有匹配的点开始寻找增广路径(增广路径性质3)。找到增广路后,根据增广路径的性质,显然路径里没被匹配的连线比已经匹配了的连线多一条(增广路径性质2),于是对增广路径中的边进行取反操作,这样匹配数就比原来多1个。不断执行上述操作,直到找不到增广路径为止,无法找到增广路径说明已达到最大匹配(增广路径性质1)。
取反操作:将增广路的匹配边变成不匹配边,不匹配边变成匹配边。
如上图所示:
- 首先从
未匹配点1
开始寻找增广路,找到了另一个未匹配点A
说明找到了增广路,停止寻找,进行取反操作,将非匹配边变为匹配边,于是1-A
为匹配边。 - 从
未匹配点2
开始寻找增广路,显然2->A->1->B
为增广路,进行取反,于是此时匹配边为2-A、1-B
。 - 从
未匹配点3
开始寻找增广路,显然3->A->2->C
为增广路,进行取反,于是匹配边变为3-A、2-C、1-B
。因为已经不存在未匹配点,此时已经找不到更多增广路径,因此达到了此二分图的最大匹配。
注:显然,二分图匹配结果并不唯一。
以上就是匈牙利算法的过程,很明显,搜寻增广路径这个步骤是基于深度优先搜索的。
匈牙利算法寻找增广路的伪代码描述:
//以下为寻找增广路并进行取反操作的伪代码,取反操作通过递归调用完成。
while(找到Xi的关联顶点Yj){if(顶点Yj不在增广路径上){将Yj加入增广路;//如果Yj是未匹配点说明成功找到增广路,从“Yj处继续寻找能够找到增广路”属于递归调用本函数过程,进行取反操作if(Yj是未匹配点||从Yj处继续寻找能够找到增广路){ 将Yj的匹配点改为Xi;return true;}}return false;
}
2、匈牙利算法的实现
网上搜索匈牙利算法,从思想上看都是基于dfs的,另外,我注意到也有一些博客提出了基于广度优先(bfs)的匈牙利算法,我不确定所谓“基于bfs的匈牙利算法”能否称为匈牙利算法,我个人的理解是匈牙利算法就是基于dfs的来寻找增广路径而实现的。
2.1、实际问题
问题描述
RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了。可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做partner和她同坐。但是,每个女孩都有各自的想法,举个例子把,Rabbit只愿意和XHD或PQK做partner,Grass只愿意和linle或LL做partner,PrincessSnow愿意和水域浪子或伪酷儿做partner。考虑到经费问题,boss刘决定只让找到partner的人去坐过山车,其他的人,嘿嘿,就站在下面看着吧。聪明的Acmer,你可以帮忙算算最多有多少对组合可以坐上过山车吗?
输入:
输入数据的第一行是三个整数K , M , N,分别表示可能的组合数目,女生的人数,男生的人数。0<K<=1000
1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。
输出:对于每组数据,输出一个整数,表示可以坐上过山车的最多组合数。
样例输入:6 3 3 1 1 1 2 1 3 2 1 2 3 3 1 0
样例输出:3
这道题本质上就是求二分图的最大匹配问题。
2.2、代码实现
Java实现:
此代码转载自https://wmathor.com/index.php/archives/1344/,//***//
表示是我添加的注释。
import java.util.Arrays;
import java.util.Scanner;public class Main {static int[][] map;static int n, m;public static void main(String[] args) {Scanner cin = new Scanner(System.in);while (cin.hasNext()) {int t = cin.nextInt();if (t == 0)break;n = cin.nextInt();m = cin.nextInt();map = new int[n + 1][m + 1];for (int i = 0; i < t; i++)map[cin.nextInt()][cin.nextInt()] = 1; // 有向边int count = 0; // 最大匹配数int[] mc = new int[m + 1]; // mc[i] = j 表示i号男生所连的女生是j号Arrays.fill(mc, -1); // 初始时所有女生都没有连//***//以下for循环是核心部分,表示依次从未匹配点开始寻找增广路径for (int i = 1; i <= n; i++) {//***//将增广路径中的结点记录下来,以免重复,因此每一次循环都必须重置。boolean[] vis = new boolean[m + 1]; // vis[i] = true 表示i号男生已经被匹配了//***//根据增广路径性质2、3,每找到一条增广路径就说明找到了一条匹配边if (dfs(i, vis, mc))count++;}System.out.println(count);}}//***//注:这个是寻找增广路径的代码,可以结合之前的伪代码,每找到一条增广路径就说明找到了一条匹配边。private static boolean dfs(int start, boolean[] vis, int[] mc) {for (int i = 1; i <= m; i++) { // 枚举男生集if (!vis[i] && map[start][i] == 1) { // 如果这个男生没被匹配并且和当前的start有边相连vis[i] = true; // 将这个男生标记为匹配过//***//以下判断语句中dfs递归调用,对应匈牙利算法中寻找增广路径并取反的操作,大家可以试着手动推理一下if (mc[i] == -1 || dfs(mc[i], vis, mc)) { // 这个男生没有和女生匹配 || 这个男生所连的女生还有别的选择,就把这个男生"腾"出来mc[i] = start;return true;}}}return false;}
}
Go:
有时间再把go的代码实现并添加过来,先画个饼。
四、总结
匈牙利算法的核心在于找增广路径,注意增广路径的三个性质。文中伪代码部分可以当成是解决这类问题的模板。
本文内容也是我自己对于算法的理解,可能存在错误,欢迎批评指正。
五、参考博客
https://blog.csdn.net/lemonxiaoxiao/article/details/108672039
https://zhuanlan.zhihu.com/p/208596378
https://www.cxyxiaowu.com/874.html
二分图完全匹配算法之匈牙利算法相关推荐
- 二分图的最大匹配(匈牙利算法)HDU1083
二分图: 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同 ...
- 二分图最大匹配问题(匈牙利算法)
什么是二分图 如果一个无向图的的顶点可以分为两个互不相交的子集A和B,那么它就是二分图.也就是说,A.B内部不存在连边,所有连边都一头连着A中的顶点,另一头连着B中的顶点. 什么是二分图最大匹配? 二 ...
- 【算法基础】二分图(染色法 匈牙利算法)
一.二分图 1. 染色法 一个图是二分图,当且仅当,图中不含奇数环.在判别一个图是否为二分图⑩,其实相当于染色问题,每条边的两个点必须是不同的颜色,一共有两种颜色,如果染色过程中出现矛盾,则说明不是二 ...
- 二分图的最大匹配:匈牙利算法,先到先得,能让则让,男生找妹子
原题链接:https://www.acwing.com/problem/content/description/863/ 左边站了一排男的,右边占了一排女的. 左边的某些男的,对右边的某些女的有好感. ...
- AcWing 861. 二分图的最大匹配(匈牙利算法)
题目连接 https://www.acwing.com/problem/content/863/ 思路 我们选择左半边或者右半边作为枚举点,然后对于当前的位置做一次判断如果当前位置的第一条边的女生已经 ...
- 匈牙利算法 求二分图最大匹配
匈牙利算法 1. 二分图 二分图: 又称作二部图,是图论中一种特殊模型.设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中每条边所关联的两个顶点 i 和 j 分别属 ...
- 浅谈匈牙利算法(二分图最大匹配)
前置知识 一张图是二分图,当且仅当它的点可以被分成两部分,而这张图上的所有边的两个端点,都分属不同的部分.我们称这两个点集,一个叫左部,一个叫右部.左部中的点叫左部点:右部中的点叫右部点. 一张图的一 ...
- 二分图带权最大匹配费用流_简单理解二分图与匈牙利算法
最近在看DETR等论文时时,看到了使用了二分图的最大匹配,对于没有计算机基础的我表示直接上来???,因此本篇博客主要介绍什么是二分图,以及二分图的匹配的匈牙利算法. 首先我们来看看二分图的定义: 二分 ...
- 第5-1课:匈牙利算法与二分图的最大匹配
在图论中,二分图(又称二部图)是一个特殊的模型,关于二分图有很多概念,比如匹配.完全匹配.最大匹配等.这一课我们来介绍一种求二分图的最大匹配的匈牙利算法,匈牙利算法原理是公开的,人们使用匈牙利算法都是 ...
- 多目标跟踪之匈牙利算法
0 前言 目标跟踪(Object Tracking)是自动驾驶中非常常见的任务,根据跟踪目标数量的不同,目标跟踪可分为: 单目标跟踪(Single Object Tracking,SOT) 多目标跟踪 ...
最新文章
- mysql数据库表的基本操作
- 服务器文件储存,文件储存服务器
- hyperopt中文文档:Recipes
- 微服务负载均衡实现高可用_使用负载平衡实现大容量可用性
- 一文带解读C# 动态拦截覆盖第三方进程中的函数(外挂必备)
- java p代表哪种数据类型_java数据类型(八种基本数据类型+三种引用类型)
- window获取历史url_Facebook 开出历史最高赏金,55,000 美元奖励十年漏洞发现者
- Puppet安装部署篇(一)
- codeforces 385C Bear and Prime Numbers
- JavaSE----数组
- 老李分享:单元测试的 5 个错误
- 手机12306买卧铺下铺技巧_购买火车票下铺实用技巧
- 高斯过程回归,得到预测标签和不确定度度
- C语言作业:统计素数并求和
- RNA甲基化修饰m6A检测热门技术—MeRIP-seq
- matlab两个图共用一个x轴_Matlab绘制多x轴和多y轴图(双x双y轴/单x双y轴/双x单y轴图等),及坐标轴参数汇总...
- Kaggle:Home Credit Default Risk 特征工程构建及可视化(2)
- [后端开发]Http请求413错误解决方法
- 使用谷歌学术检索论文小技巧
- magento怎么修改货币符号,在之前加上国家缩写
热门文章
- 计算机服装辅助设计,计算机辅助高校服装设计的论文
- fastjson笔记
- SFTP服务器文件下载
- Matlab实现二维数字图像相关(2D Digital Image Correlation, 2D-DIC)【ADIC2D代码复现及原理介绍】
- 在MATLAB下安装Matpower模块
- UnDistort Audio File(音频修复软件)官方正式版V1.0 | 音频修复软件哪个好用 | 专业修复音频的软件
- ps安装 Photoshop CC2017 安装,cutterman下载安装,ps简单设置
- docker 安装svnserver
- 【电机控制入门】——电机控制书籍推荐
- [Bug]Superset通过pyhive连接Spark SQL表名获取失败