匈牙利算法是用来求二分图的最大匹配的,它的核心问题就是找增广路径。匈牙利算法的时间复杂度为O(VE),
其中V为二分图左边的顶点数,E为二分图中边的数目。
增广路的特性:
(1)有奇数条边。
(2)起点在二分图的左半边,终点在右半边。
(3)路径上的点一定是一个在左半边,一个在右半边,交替出现。
(4)整条路径上没有重复的点。
(5)起点和终点都是目前还没有配对的点,而其它所有点都是已经配好对的。
(6)路径上的所有第奇数条边都不在原匹配中,所有第偶数条边都出现在原匹配中。
(7)最后,也是最重要的一条,把增广路径上的所有第奇数条边加入到原匹配中去,并把增广路径中的所有第偶
数条边从原
匹配中删除(这个操作称为增广路径的取反),则新的匹配数就比原匹配数增加了1个。
很多问题都可以转化为二分图匹配模型。二分图有如下几种常见变形:
(1)二分图的最小顶点覆盖
最小顶点覆盖要求用最少的点(X或Y中都行),让每条边都至少和其中一个点关联。
Knoig定理:二分图的最小顶点覆盖数等于二分图的最大匹配数。
(2)DAG图的最小路径覆盖
用尽量少的不相交简单路径覆盖有向无环图(DAG)G的所有顶点,这就是DAG图的最小路径覆盖问题。
结论:DAG图的最小路径覆盖数 = 节点数(n)- 最大匹配数(m)
(3)二分图的最大独立集
最大独立集问题: 在N个点的图G中选出m个点,使这m个点两两之间没有边.求m最大值
结论:二分图的最大独立集数 = 节点数(n)— 最大匹配数(m)
例如:
#include<iostream>
using namespace std;
#define N 4
#define M 4
int rightnode[M+1] = {0};
bool line[N + 1][M + 1] = { { 0, 0, 0, 0, 0 },
{ 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0 },
{ 0, 1, 1, 0, 0 },
{ 0, 0, 0, 1, 0 }
};
bool used[M+1] = {false};
bool search_road(int x){
for (int i = 1; i <=M;i++)
{
if (line[x][i] == true && used[i] == false){
used[i] = true;
int temp = rightnode[i];
if (temp == 0 || search_road(rightnode[i])){
rightnode[i] = x;
return true;
}
}
}
return false;
}
int getMaxNum(){
int max = 0;
for (int i = 1; i <= N;i++)
{
for (int j = 1; j <=M; j++) used[j] = false;
if (search_road(i)) max++;
}
return max;
}