匈牙利算法在手,孟非都为你亮灯。
在学习匈牙利算法之前,要先了解二分图
二分图又称作二部图,是图论中的一种特殊模型。
设G=(V,{R})是一个无向图。如顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属两个不同的子集。则称图G为二分图。
感性理解:两个互不相交的子集就像男生和女生,男女有别。。。
然后就是最大匹配
给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
感性理解:一个男的喜欢一个女的,恰巧女的也喜欢男的,然后就叫一个匹配
对于选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem)
然后。。。
就引出主题匈牙利算法(感性理解:就是最优相亲算法)
有一种感性的理解:一群剩男剩女进行组成伴侣,在不同性恋、不一夫多妻、一妻多夫的情况下撮合尽可能多的情侣
对于一个问题,形如
你是孟非老师,在《非诚勿扰》牵桥搭线,现在有19位男嘉宾,和24位女嘉宾,现在你已成功搭配了19对,后来又来了4位男嘉宾每位男嘉宾都有自己有好感的女嘉宾,而每位女嘉宾都给自己喜欢的男嘉宾亮灯。你,孟非老师,有一个远大的理想,想让世界上有更多的cp,那该如何配对
关系如下图
1号男嘉宾——菜老师对女嘉宾有好感,同理,都亮灯了
有线连着的表示互有好感
1号菜老师直接强上1号女嘉宾,2号男连只能连2号女,这时,牵线正爽的你发现了问题
尴尬的3号男失去了唯一的机会
这时只能重新看到占有3号男梦想的2号男,让他给3号男一个机会
而2号男只能强连1号女,green 了菜老师,菜老师无奈重连3号女
然后你就挽回了3号男的梦想
然后4号男直接强上5号女
完成了最大匹配,送走了最后的可怜剩女
最后不难发现最大牵线的重点在于创造机会
正如 时间告诉我的,说过的话可以算了,爱的人可以再换
所以创造机会的关键就在于换人一词
而换人就要根据需求一个一个往上换,换到合适或实在不行为止
思路灵感来源
奉上一段代码,理解消化啦啦啦
#include
#include
#include
#include
#include
#include
using namespace std;
vector G[307] ;
int n , m , ans ;
int M[307] ;
bool vis[307] ;
bool dfs( int f ) {//DFS牵线
for(int i = 0 ; i < G[f].size() ; ++ i ) {
int s = G[f][i] ;
if( !vis[s] ) {
vis[s] = 1 ;
if( M[s] == -1 || dfs( M[s] ) ) {
M[s] = f ;//如果名花无主或可以换人就直接强上
return 1 ;
}
}
}
return 0;
}
int main()
{
scanf("%d%d", &n , &m );
for(int i = 1 ; i <= n ; ++ i ) {//基本输入
int sum ;
scanf("%d", &sum );
for(int j = 1 ; j <= sum ; ++ j ) {
int num ;
scanf("%d", &num );
G[i].push_back(num);
}
}
memset( M , -1 , sizeof( M ) );//女嘉宾全部赋为 名花无主 标记
for(int i = 1 ; i <= n ; ++ i ) {
memset( vis , 0 , sizeof( vis ) );//每一次牵线都要重置是否访问
if( dfs(i) )
ans ++ ;
}
printf("%d", ans );
return 0;
}
最后的理论证明
在学习中,就算是孟非老师或菜老师,也是需要理论知识支撑的,这样才能成为本世纪最伟大的 Matchmacker (红娘,媒婆的意思)
(先了解一下命题)
定理:存在增广链是增广当前匹配的充要条件
等价的命题是,为什么在当前匹配下不存在以左边某一未匹配点开始的增广链,该点就不是当前匹配下增广的必要点,即该点不能增广当前匹配。
从匹配增广的原理可以看出,以该点开始的增广链是该点可以增广当前匹配的充分条件
必要条件?
首先能理解的是:如果增广路径从左边开始终止在左边点
路径上已经选择的边和没有被选择的边数量相同
按照前面介绍进行增广操作并不能增加比配边数
然后用反证法去证明如果该点能改善匹配,那么就一定存在,不需要改变原来匹配点集合的(已经匹配的点一定在改善后的匹配中),以该点开始的增广链
在这里假设已经匹配的左边点为,对应的右边点为
如果该点能改善匹配,那么根据匹配的独立性,必然在改善后的匹配中,右边也有个点,而且,只需要一个新的右边点加入匹配即可(这个可以从下面的分析中可以看出)
1.如果在改善的匹配中,匹配的是新点,那么就是一条增广链
2.如果匹配的不是新点,那么假设匹配的是,在原来匹配中匹配对象是,根据匹配唯一性,在改善后的匹配中匹配的肯定不是,如果匹配的是新点,那么就是一条增广链
3.如果匹配的还是原来匹配的点,那就继续上面的分析2,根据已经匹配点数量是有限的,当分析到最后一个左边点时,根据匹配的唯一性,它必然和新点连接(因为旧点只有k个),那么增广链依然存在(开始,结束,中间穿过所有的和)
综上分析,如果存在改善匹配包含了该新点,那么就必然存在一条以该点开始的增广链,而且新增的右边点仅仅有一个,不需要另外的点去替换原来的右边点
引理:那么根据存在增广链是增广当前匹配的充要条件,算法只要遍历所有未匹配的左边点,没有找到增广链,即可终止算法,找到最大匹配
另外一方面
定理:在目前的匹配情况下
没有搜索到以该点开始的增广路径
在后面加入别的点的匹配情况下,也不可能有以该点开始的增广路径存在
(这个保证了算法只要遍历一遍左边点即可,不需要重复遍历)
证明:
原来的匹配为,对应的右边点为
如果加入新点和时,所使用的增广链为,改善后的匹配变成和对应的,p=k+1
前提:在原来的匹配下没有增广路径
假设在改善后的匹配下存在增广路径
1、如果增广路径中不存在, 中的,那么增广路径肯定不存在,因为改善匹配中存在匹配,所以
中的和都是原匹配中的,因此这是原匹配中的一条增广路径,和前提相悖
2、如果增广路径中存在, 中的,那么原匹配中必然存在增广路径,也是原匹配中的一条增广路径,和前提相悖
综上即证
证明原创出处:https://blog.csdn.net/qq_25379821/article/details/83721379
学完后,你就是一个合格的 Matchmacker