学习笔记 匈牙利算法

匈牙利算法是一种精妙的算法,我一开始都不敢相信他是对的。

先来看定义:

  • 匹配 匹配是一个边集,其中任意两条边都没有公共端点。
  • 最大匹配 顾名思义,包含边数最多的匹配
  • 交错路 匹配边和非匹配边依次出现的一条路
  • 增广路 从非匹配边出发,以非匹配边结束的交错路(增广路长度一定是奇数)

感觉好奇怪啊

匈牙利算法的基本思想,就是不断地扩大匹配的集合,不断尝试让匹配边数加一。匹配边数不能变多了,算法也就结束了。

有两条性质,乍一看很显然,其实很难证:

  • 一个匹配(M)是最大匹配,当且仅当图中不存在增广路。
  • 从某一点(左部点)出发,如果某个时刻找不到增广路,那就永远都找不到了。

性质1的必要性是显然的,让我们先来看算法的过程。

我们首先给二分图定向(说人话就是划分出左部和右部,规定增广路从左部出发)。枚举每一个左部点(是非匹配点),如果能找到增广路,我们就把增广路上所有边的状态取反,得到一种大小+1的匹配。
复杂度(O(nm)) (点数*边数)

结合代码理解一下

int vis[mxn],mch[mxn];//match
inline bool hungary(int x){
    if(vis[x])return 0;vis[x]=1;
//vis记录左部点右部点皆可
    for(int i=first[x];i;i=nxt[i]) //边是单向边
        if(!mch[to[i]] || hungary(mch[to[i]]))return mch[to[i]]=x,1;
    return 0;
}

//main函数
int ans=0;
for(int i=1;i<=n;++i)memset(vis,0,sizeof(vis)),ans+=hungary(i);

我们回过头看这两个性质,性质1是算法的基础,性质2确保了每个点只搜一次。

对证明感兴趣的可以看队爷论文,写的可好了,适合初学者看。

可以再看看 hall定理 虽然本文没有用到

好像还能用bfs写,据说常数更小。

以上。

原文地址:https://www.cnblogs.com/happyguy/p/13485224.html