C++学习笔记:浅析匈牙利算法

引言

匈牙利算法在手,孟非都为你亮灯。


二分图&最大匹配

在学习匈牙利算法之前,要先了解二分图

二分图又称作二部图,是图论中的一种特殊模型。

设G=(V,{R})是一个无向图。如顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属两个不同的子集。则称图G为二分图。

感性理解:两个互不相交的子集就像男生和女生,男女有别。。。

然后就是最大匹配

给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。

感性理解:一个男的喜欢一个女的,恰巧女的也喜欢男的,然后就叫一个匹配


匈牙利算法

对于选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem)

然后。。。

就引出主题匈牙利算法(感性理解:就是最优相亲算法)

有一种感性的理解:一群剩男剩女进行组成伴侣,在不同性恋不一夫多妻一妻多夫的情况下撮合尽可能多的情侣

对于一个问题,形如

你是孟非老师,在《非诚勿扰》牵桥搭线,现在有19位男嘉宾,和24位女嘉宾,现在你已成功搭配了19对,后来又来了4位男嘉宾每位男嘉宾都有自己有好感的女嘉宾,而每位女嘉宾都给自己喜欢的男嘉宾亮灯。你,孟非老师,有一个远大的理想,想让世界上有更多的cp,那该如何配对

关系如下图

C++学习笔记:浅析匈牙利算法_第1张图片

1号男嘉宾——菜老师对女嘉宾有好感,同理,都亮灯了

有线连着的表示互有好感

牵线时间

1号菜老师直接强上1号女嘉宾,2号男连只能连2号女,这时,牵线正爽的你发现了问题

尴尬的3号男失去了唯一的机会

C++学习笔记:浅析匈牙利算法_第2张图片

 

这时只能重新看到占有3号男梦想的2号男,让他给3号男一个机会

而2号男只能强连1号女,green 了菜老师,菜老师无奈重连3号女

然后你就挽回了3号男的梦想

然后4号男直接强上5号女

完成了最大匹配,送走了最后的可怜剩女

C++学习笔记:浅析匈牙利算法_第3张图片


牵线总结

最后不难发现最大牵线的重点在于创造机会

正如 时间告诉我的,说过的话可以算了,爱的人可以再换

所以创造机会的关键就在于换人一词

而换人就要根据需求一个一个往上换,换到合适或实在不行为止

思路灵感来源


代码

奉上一段代码,理解消化啦啦啦

​
​
#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 

 

你可能感兴趣的:(图论)