- 匈牙利算法的概述
用来解决二分图中的最优分配问题的算法,也就是图论中寻找最大匹配的算法。
- 从实际问题的角度理解(\(\mbox{KM}\)算法)
- 第(1)步:找到每个成员的长处,即寻找各个成员完成各任务的最短耗时。将成本矩阵的各行减去该行的最小值,找出各行的“0”;
- 第(2)步:找到各任务的最佳人选,即寻找各任务分配给各成员完成的最短耗时。将(1)中处理后的成本矩阵的各列减去该列的最小值,找出各列的“0”;
- 第(3)步:成员和任务的礼让原则。相对不能“将就”的成员和任务优先选择。
- 成员礼让原则。寻找长处最少的成员,先把他的长处分配给他,因为长处越多的成员越容易调配。在(2)中处理后的成本矩阵中找到含有“0”最少的行,然后将该行的“0”画上圈(记为\(\circledcirc\)),同时由于一个任务同一时刻只能由一个成员完成,故划去其所在列的其他“0”(记为\(\phi\));
- 任务礼让原则。寻找最佳成员最少的任务,先把它的最佳成员分配给它,原因同(3)。在(3)中处理后的成本矩阵中找到含有“0”最少的列,然后将该列的“0”画上圈(记为\(\circledcirc\)),同时由于一个成员同一时刻只能完成一个任务,故划去其所在行的其他“0”(记为\(\phi\));
- 第(4)步:寻找牺牲的成员和任务。方法为打钩划线法。
- 打钩。对(3)中处理后的成本矩阵中不含“\(\circledcirc\)”的行打钩(寻找牺牲成员\(M_1\)),然后对该行中含有“\(\phi\)”的列打钩(寻找该成员与其他成员相冲突的任务\(T_1\)),再对该打钩列中含有“\(\circledcirc\)”的行打钩(寻找完成该冲突任务\(T_1\)的其他成员\(M_2\))。若\(M_2\)中还有与其他成员冲突的任务,则重复上述步骤,反之则结束打钩过程;
- 划线。寻找有任务冲突的所有成员,然后提取出他们无冲突的任务,为之后的重新分配)做准备。对未打钩的行(无任务冲突的成员)和已打钩的列(冲突任务)划线排除。
- 第(5)步:重新调度分配。找到所有有任务冲突的成员,标记出他们的无冲突任务,最后选择耗时最少的任务作为“激励”/“惩罚”因子。在(4)中处理后的成本矩阵中寻找未被划线元素的最小值,然后对打钩行减去这个最小值、对打钩列增加这个最小值。
- 对打钩行减去这个最小值:在增加“0”的同时也能对冲突成员的无冲突任务进行“激励”。如果这次分配失败,则下一次分配时这些任务会更先被分配;
- 对打钩列增加这个最小值:在保证任务耗时非负的同时也能对有冲突任务进行“惩罚”。如果这次分配失败,则下一次分配时这些任务会更后被分配;
- 第(6)步:如果出现各行各列都只有一个“\(\circledcirc\)”则说明分配成功,否则分配失败,重复(4)~(6)。
- 从图论理论的角度理解(匈牙利算法)
- 专有名词解释
- 匹配\(\mbox{M}\):是边集\(\mbox{E}\)的一个无环子集,且它的任意两条边在图\(\mbox{G}\)中都不相邻;
- \(\mbox{M}\)的饱和顶点\(\nu\):\(\exists{e}\in{M}\)与顶点\(\nu\)关联;
- \(\mbox{M}\)的非饱和顶点\(\nu\):\(\forall{e}\in{M}\)不与顶点\(\nu\)关联;
- 最大匹配\(\mbox{M}\):所有匹配中边数最多的匹配方案;
- 完美匹配\(\mbox{M}\):某个匹配包含了图\(\mbox{G}\)中所有的顶点;
- 交错路径
\(M\)是图\(G\)某匹配,若某路径在\(M\)和\(G-M\)中交替出现,则将这条路径称为\(M\)交错路径。
- 增广路径
如果一条\(M\)交错路径的起点和终点都是\(M\)非饱和顶点,则称为\(M\)增广路径。
- 算法步骤
- 我的理解
- 算法的目标
任取一个\(M(X)\)非饱和顶点\(x_0\)作为“入射源点”,经过或者不经过\(M\)匹配中的“反射”,最后需要找到一个\(M(Y)\)非饱和顶点\(y_0\)作为“出射终点”,这样一条“反射光线”被称为“\(M\)增广路径”。
- 算法的遍历思想
有点儿类似于层序遍历的思想。将\(N(S)\)作为访问备选方案,将其中已经访问过的\(Y\)做上标记(用集合\(T\)表示),以便后续不再重复访问(\(y\in{N(S)-T}\))。
在访问\(Y\)中结点之前必须对\(N(S)\)做判断,查看是否全被访问过(即\(N(S)\subseteq{T}\)),而对于每一个被访问的\(Y\)结点都会判断其是否属于\(M(Y)\)饱和顶点:
- 如果属于\(M(Y)\)饱和顶点:将与之\(M\)匹配的\(X_i\)并入\(S\),并将\(y\)并入访问标记\(T\)中;
- 如果不属于\(M(Y)\)饱和顶点:必然存在一条增广路径\(P(x_0,y_0)\),\(M=M\oplus{E(P)}\);
- 如何获取增广路径
可以用\(\mbox{DFS}\)(深度优先搜索)算法。
- 赋权二部图最大匹配\(\mbox{Kuhn-Munkres}\)算法
- 顶点标号与可行顶点标号
图\(G\)的顶点标号\(l\)是从顶点集到正整数集的一个映射。用\(l(\nu)\)为\(G\)上顶点\(\nu\)的标号,边\(<\nu_1,\nu_2>\)的权重用\(\omega(\nu_1\nu_2)\)表示。如果对于赋权二部图\(G\)中的每一条边\(<x,y>\)都有\(l(x)+l(y)\ge\omega(xy)\),则称这个标号\(l\)是图\(G\)的一个可行顶点标记。
其意义在于权重\(\omega(xy)\)是固定的,只有顶点的标号是随意初始化的。
每次访问\(y\)都需要对其施加“惩罚”(\(+\))\(\alpha_l\),而对与之匹配的\(x\)施加“激励”(\(-\))\(\alpha_l\)。
通常选择\(l(x_i)=\underset{y\in{Y}}{\max}{(\omega(xy))}\),\(l(y_i)=0\),然后通过不断地调整\(l(x)\)和\(l(y)\)使得\(l(x)+l(y)\rightarrow\omega(xy)\)。
- 相等子图的概念以及推论
- 相等子图
令\(E_l=\{xy\in{E(G)|l(x)+l(y)=\omega(xy)}\}\)(也就是匹配),则\(G(E_l)\)为\(G\)的\(l\)相等子图\(G_l\)。
- 定理推论
相等子图\(G_l\)的完美匹配,亦是\(G\)的最大权完美匹配。
- \(\mbox{KM}\)算法优化方法及步骤
- 如果\(\norm{X}\neq\norm{Y}\),则给\(G(X,Y)\)添加一些顶点和权为0的边,使其成为赋权二部图。
- 从\(G\)中任意一可行顶点标号开始,求出相等子图\(G_l\)(初始化一个匹配\(M\))。
- 在\(G_l\)中执行匈牙利算法,观察是否能够输出一个完美匹配\(M\):
- 如果可以求得完美匹配\(M\),则将其输出并停止;
- 否则重新对顶点标号赋值:所有访问过的\(y\)都需要对其施加“惩罚”(\(+\))\(\alpha_l\),而与它们匹配的\(x\)施加“激励”(\(-\))\(\alpha_l\),其余的顶点标号不变。
\[\alpha_l\overset{\Delta}{=}\underset{x\in{S},y\notin{T}}{\min}{\{l(x)+l(y)-\omega(xy)\}},其中S=\mbox{visited}_x,T=\mbox{visited}_y \]
也就是说使得\(\mbox{visited}_{x}\)有更多的\(y\)与之匹配,而限制\(\mbox{visited}_y\)的匹配数量。