匈牙利算法是一种在多项式时间内求解任务分配问题的组合优化算法,并推动了后来的原始对偶方法。——————百度百科
咳咳,匈牙利算法是一种常用于求二分图最大匹配的高效算法,将暴力的指数级算法进化到多项式复杂度,如果用邻接表存图,最坏时间复杂度为O(nm)。
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
二分图最大匹配是指在二分图中,所有匹配中包含最多匹配边的匹配。在二分图中,顶点被分为两个互不相交的子集,图中的每条边连接这两个子集的顶点。最大匹配是指在一个图中所有可能的匹配中,匹配边数最多的匹配。其中,一个匹配中所有边互不相交,即没有公共点。
二分图最小点覆盖是指选出最少数量的点,构成点集V ,二分图中的每条边都至少有一个顶点在点集V中。
二分图最大独立集是指在二分图的点全集V中,选出最多数量的点,使得这些点在原图中互相没有边联通。
这里给出一些变换公式:
以下设二分图的点全集为V。
最小点覆盖=最大匹配。
最大独立集=|V|-最小点覆盖=|V|-最大匹配
笔者认为,匈牙利算法的主要流程是这样:从左部点(或右)枚举每个点,将这个点与有边联通的右部点匹配,如果右部点已经有匹配,继续判断这个匹配能不能和另外一个右部点匹配。
以上是基于深度优先的匈牙利算法。
下面附上模板题
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 510;
int n, m, E;
vector <int> e[N];//动态数组存图
int vis[N], match[N];//vis表示这个右部点是否被访问过,match表示这个右部点的匹配
int path(int u)
{
for (int v : e[u])
{
if (!vis[v])//记录vis是为了防止后续重复访问,影响正确性
{
vis[v] = 1;
if (!match[v] || path(match[v]))//如果右部点还没有匹配,或者其匹配可以匹配别的匹配()
{
match[v] = u;//更新匹配
return 1;
}
}
}
return 0;
}
void mian()
{
cin >> n >> m >> E;
int u, v;
for (int i = 1; i <= E; i ++)
{
cin >> u >> v;
e[u].push_back(v);
}
int ans = 0;
for (int i = 1; i <= n; i ++)
{
if (path(i)) ans ++;
memset(vis, 0, sizeof(vis));//每次枚举完都要清空
}
cout << ans << endl;
}
int main()
{
int T = 1;
while (T --) mian();
return 0;
}