博客推荐:KM算法详解 我对KM算法的理解 二分图的最佳完美匹配--KM算法
1、KM算法是用于寻找带权二分图最佳匹配的算法。 对KM算法的描述,基本上可以概括成以下几个步骤:
(1) 初始化可行标杆
(2) 用匈牙利算法寻找完备匹配
(3) 若未找到完备匹配则修改可行标杆
(4) 重复(2)(3)直到找到相等子图的完备匹配
2、二分图详解:
(1)二分图定义:
所有顶点可以分成两个集:X和Y,其中X和Y中的任意两个在同一个集中的点都不相连,而来自X集的顶点与来自Y集的顶点有连线。当这些连线被赋于一定的权重时,这样的二分图便是带权二分图。
(2)二分图判定:
无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。判断无向连通图是不是二分图,可以使用深度优先遍历算法(又名交叉染色法)。下面着重介绍下交叉染色法的定义与原理
首先任意取出一个顶点进行染色,和该节点相邻的点有三种情况:
a.如果节点没有染过色,就染上与它相反的颜色,推入队列,
b.如果节点染过色且相反,忽视掉,
c.如果节点染过色且与父节点相同,证明不是二分图,return
(3)二分图匹配:
二分图匹配是指求出一组边,其中的顶点分别在两个集合中,且任意两条边都没有相同的顶点,这组边叫做二分图的匹配,而所能得到的最大的边的个数,叫做二分图的最大匹配。 我们也可以换个角度看二分图的最大匹配,即二分图的每条边的默认权重为1,我们求到的二分图的最大匹配的权重最大。对于带权二分图,其边有大于0的权重,找到一组匹配,使其权重最大,即为带权二分图的最佳匹配。
3、增广路径:
(1)增广路径定义比较晦涩难懂,直接看它的特性更清晰一些,增广路径有如下特性:
(2)找增广路径的过程:目前图中只有(X0, Y0)匹配成功,也就是说蓝色这条线是已匹配子图(目前只有一条边),现在X1想要配对,只能和Y0进行配对,但发现Y0已经被X0匹配了,于是就深入到X0,去为X0找新的匹配节点,发现X0可以和Y2匹配,而且Y2处于未匹配状态,因此通过X1找到了增广路径:X1Y0->Y0X0->X0Y2
其中第奇数第边x1y0和x0y2不在当前的匹配子图中,而第偶数条边x0y0在匹配子图中,通过添加x1y0和x0y2到匹配子图并删除x0y0,使得匹配数由1增加到了2。每找到一条增广路径,通过添加删除边,我们总是能使匹配数加1。
增广路径有两种寻径方法,一个是深搜,一个是宽搜。
例如从x2出发寻找增广路径
4、匈牙利算法:
匈牙利算法一般用于寻找二分图的最大匹配。算法根据一定的规则选择二分图的边加入匹配子图中,其基本模式为:
初始化匹配子图为空
While 找得到增广路径
Do 把增广路径添加到匹配子图中
匈牙利算法就是在不断寻找增广路,如果找不到增广路,就说明达到了最大匹配。
匈牙利算法代码:
//---------------------DFS---------------------------------
#include
#include
using namespace std;
#define MAXN 10
int graph[MAXN][MAXN];
int match[MAXN];
int visitX[MAXN], visitY[MAXN];
int nx, ny;
bool findPath( int u )
{
visitX[u] = 1;
for( int v=0; v
#include
using namespace std;
#define MAXN 10
int graph[MAXN][MAXN];
//在bfs中,增广路径的搜索是一层一层展开的,所以必须通过prevX来记录上一层的顶点
//chkY用于标记某个Y顶点是否被目前的X顶点访问尝试过。
int matchX[MAXN], matchY[MAXN], prevX[MAXN], chkY[MAXN];
int queue[MAXN];
int nx, ny;
int bfsHungarian()
{
int res = 0;
int qs, qe;
memset( matchX, -1, sizeof(matchX) );
memset( matchY, -1, sizeof(matchY) );
memset( chkY, -1, sizeof(chkY) );
for( int i=0; i= 0 )
prevX[matchY[v]] = u;
else //到达了增广路径的最后一站
{
flag = 1;
int d=u, e=v;
while( d!=-1 ) //一路通过prevX找到路径的起点
{
int t = matchX[d];
matchX[d] = e;
matchY[e] = d;
d = prevX[d];
e = t;
}
}
}
}
qs++;
}
if( matchX[i] != -1 )
res++;
}
}
return res;
}
5、KM算法:
(1)KM算法,用于求二分图匹配的最佳匹配。何为最佳匹配?就是带权二分图的权值最大的完备匹配称为最佳匹配。 那么何为完备匹配?X部中的每一个顶点都与Y部中的一个顶点匹配,或者Y部中的每一个顶点也与X部中的一个顶点匹配,则该匹配为完备匹配。
KM算法的最大特点在于利用标杆和权重来生成一个二分子图,在该二分子图上面找最大匹配,而且,当些仅当找到完备匹配,才能得到最佳匹配。标杆和权重的作用在于限制新边的加入,使得加入的新边总是能为子图添加匹配数,同时又令权重和得到最大的提高。
(2)KM算法步骤:
(3)KM算法顶标
二分图最佳匹配还是二分图匹配,所以跟和匈牙利算法思路差不多。二分图是特殊的网络流,最佳匹配相当于求最大(小)费用最大流,所以FF算法(全名Ford-Fulkerson算法)也能实现。
但是遇到某个点被匹配了两次怎么办?那就用匈牙利算法进行更改匹配!所以,根据KM算法的思路,我们一开始要对边权值最大的进行连线。那问题就来了,我们如何让计算机知道该点对应的权值最大的边是哪一条?或许我们可以通过某种方式记录边的另一端点,但是呢,后面还要涉及改边,又要记录边权值总和,而这个记录端点方法似乎有点麻烦。于是KM采用了一种十分巧妙的办法(也是KM算法思想的精髓):添加标杆(顶标)
添加标杆(顶标)流程:
添加顶标之前的二分图:
添加顶标之后的二分图:
(4)KM算法原理、流程、伪代码