zoukankan      html  css  js  c++  java
  • 二分图匹配--匈牙利算法

    二分图匹配--匈牙利算法

    基本定义:

    二分图 —— 对于无向图G=(V,E),如果存在一个划分使V中的顶点分为两个互不相交的子集,且每个子集中任意两点间不存在边 ϵ∈E,则称图G为一个二分图。

    二分图的充要条件是,G至少有两个顶点,且所有回路长度为偶数。

    匹配 —— 边的集合,其中任意两条边都不存在公共顶点。
    匹配边即是匹配中的元素,匹配点是匹配边的顶点,同样非匹配边,非匹配点相反定义。

    最大匹配——在图的所有匹配中,包含最多边的匹配成为最大匹配
    完美匹配——如果在一个匹配中所有的点都是匹配点,那么该匹配称为完美匹配。

    附注:所有的完美匹配都是最大匹配,最大匹配不一定是完美匹配。假设完美匹配不是最大匹配,那么最大匹配一定存在不属于完美匹配中的边,而图的所有顶点都在完美匹配中,不可能找到更多的边,所以假设不成立,及完美匹配一定是最大匹配。

    交替路——从一个未匹配点出发,依次经过非匹配边,匹配边,非匹配边…形成的路径称为交替路,交替路不会形成环。

    增广路——起点和终点都是未匹配点的交替路。
    因为交替路是非匹配边、匹配边交替出现的,而增广路两端节点都是非匹配点,所以增广路一定有奇数条边。而且增广路中的节点(除去两端节点)都是匹配点,所属的匹配边都在增广路径上,没有其他相连的匹配边,因此如果把增广路径中的匹配边和非匹配边的“身份”交换,就可以获得一个更大的匹配(该过程称为改进匹配)。

    示例图

    enter description here

    Fig1_09_09.JPG
    enter description here
    enter description here

    注释

    • Fig3是一个二分图G=(V,E),V={1,2,3,4,5,6,7,8},E={(1,7),(1,5),(2,6),(3,5),(3,8),(4,5),(4,6)},该图可以重绘成Fig4,V可分成两个子集V={V1,V2},V1={1,2,3,4},V2={5,6,7,8}。

    • Fig4中的红色边集合就是一个匹配{(1,5),(4,6),(3,8)}

    • Fig2中是最大匹配

    • Fig1中红色边集合是完美匹配

    • Fig1中交替路举例(4-6-2-7-1-5)

    • Fig4中增广路(2-6-4-5-1-7)

    匈牙利树

    匈牙利树中从根节点到叶节点的路径均是交替路,且匈牙利树的叶节点都是匹配点。
    匈牙利算法
    求解最大匹配的算法,通过不断的寻找增广路径,并将增广路径进行改进匹配,直至找不到更多的增广路径。
    二分图的最大匹配可以通过匈牙利树的搜索寻找增广路径来获得,而树的搜索可以使用深度优先搜索(DFS)或者广度优先搜索(BFS)
    下面使用matlab代码实现DFS和BFS下的匈牙利算法:

    1. function Hungarian(c1, m, IsDraw) 
    2. % 匈牙利算法寻找无向二分图的最大匹配 
    3. % inputs: 
    4. % -AdjTable 顶点元素的邻接表,cell结构,每一个元素是一个一维数组, 
    5. % 保存对应节点的邻接节点编号 
    6. % -c1 第一个顶点子集元素个数 
    7. % -m 搜索方法,'B'是广度优先搜索,‘D’是深度优先搜索 
    8. % -IsDraw 是否绘图 
    9.  
    10. if nargin<2 
    11. m='B'
    12. IsDraw=0
    13. elseif nargin<3 
    14. IsDraw=0
    15. end 
    16.  
    17. global MatTable Check AdjTable 
    18. % -MatTable 匹配表,长度为顶点个数,每个元素存放该节点所在匹配边的另一端节点 
    19. % 的编号;如果是非匹配点,则对应值为0 
    20. cn=length(AdjTable);%顶点个数 
    21. MatTable=zeros(1,cn);% 默认都是未匹配点 
    22. Check = zeros(1,cn); % 覆盖过的点不能再访问,否则死循环 
    23.  
    24. EdgesNum=0;% 最大匹配中元素个数 
    25. if m=='D' % 深度优先搜索 
    26. if c1<cn-c1 
    27. for i=1:c1 
    28. if DFS(i
    29. EdgesNum=EdgesNum+1
    30. end 
    31. end 
    32. else 
    33. for j=c1+1:cn 
    34. if DFS(j
    35. EdgesNum=EdgesNum+1
    36. end 
    37. end  
    38. end 
    39. else % 广度优先搜索 
    40. EdgesNum = BFS(c1);  
    41. end 
    42. fprintf('There is %f edges in the biggest matches. ',EdgesNum); 
    43. if IsDraw 
    44. c2=cn-c1; 
    45. X1=ones(c1,1)*40
    46. Y1=20:10:c1*10+19
    47. X2=ones(c2,1)*100
    48. Y2=20:10:c2*10+19
    49. X=[X1;X2]
    50. Y=[Y1';Y2']
    51. color={'ro:','ko:'}
    52. for i=1:cn 
    53. if MatTable(i)~=0 
    54. plot(X(i),Y(i),color{1},'MarkerSize',15);hold on  
    55. if i<=c1 
    56. text(X(i)-3,Y(i),num2str(i)); 
    57. else 
    58. text(X(i)+3,Y(i),num2str(i)); 
    59. end 
    60. else 
    61. plot(X(i),Y(i),color{2},'MarkerSize',15);hold on 
    62. if i<c1 
    63. text(X(i)-3,Y(i),num2str(i)); 
    64. else 
    65. text(X(i)+3,Y(i),num2str(i)); 
    66. end 
    67. end 
    68. end 
    69. for i=1:cn 
    70. for j=1:length(AdjTable{i}
    71. if MatTable(i)==AdjTable{i}(j
    72. plot(X([i,AdjTable{i}(j)]),Y([i,AdjTable{i}(j)]),'r.-','LineWidth',2);hold on 
    73. else 
    74. plot(X([i,AdjTable{i}(j)]),Y([i,AdjTable{i}(j)]),'k.-','LineWidth',2);hold on 
    75. end 
    76. end 
    77. end 
    78. box('on'
    79. axis off 
    80. hold off 
    81.  
    82. end 
    83.  
    84.  
    85. end 
    86. % AdjTable 邻接表 
    87. % MatTable 匹配表 
    88. function bool=DFS(u) 
    89. % n 是左侧未匹配点的编号 
    90. % 寻找节点n的一条未匹配边 
    91. global AdjTable MatTable Check 
    92. for i=1:length(AdjTable{u}
    93. v=AdjTable{u}(i); 
    94. if ~Check(v) 
    95. Check(v)=1
    96. if MatTable(v) == 0|| DFS(MatTable(v))  
    97. %v是未匹配点则找到增广路径,交换身份 
    98. %否则,如果v的匹配点存在增广路径, 
    99. %那么也是找到一条增广路径 
    100. % || 是短路运算符 
    101. MatTable(u) = v; 
    102. MatTable(v) = u; 
    103. bool=1
    104. return;  
    105. end  
    106. end 
    107. end 
    108. bool=0
    109. end 
    110.  
    111. function EdgeNum=BFS(c1) 
    112. global AdjTable MatTable Check 
    113. pre = zeros(length(AdjTable))-1
    114. % 存放的是该点所在的非匹配边的前一个非匹配边的右端端点编号 
    115. queue=[];% 广度优先搜索需要的搜索队列 
    116. EdgeNum=0;%最大匹配元素个数 
    117. for i=1:c1 
    118. if ~MatTable(i) % 寻找未匹配点 
    119. queue=[i];%入队列 
    120. flag = 0; % 未找到增广路径 
    121. pre(i)=-1; % 为了最后改进路径时设定终点  
    122. while(~isempty(queue)&&~flag) 
    123. u=queue(1); 
    124. queue(1)=[];%出队列 
    125. edges=AdjTable{u}
    126. for j=1:length(edges) 
    127. v = edges(j); 
    128. if ~flag && Check(v)~=i 
    129. Check(v)=i
    130. queue=[queue,MatTable(v)]
    131. %找到一条匹配路,将匹配路的右端节点放入队列 
    132. if MatTable(v) % 非增广路 
    133. pre(MatTable(v))=u; 
    134. %下一条非匹配边的起点对应前一条非匹配边的起点 
    135. else % 找到增广路径 
    136. flag=1
    137. d=u; 
    138. e=v; 
    139. while d~=-1 
    140. t = MatTable(d); 
    141. MatTable(d)=e; 
    142. MatTable(e)=d; 
    143. d = pre(d); 
    144. e = t; 
    145. end 
    146. end 
    147. end 
    148. end 
    149. end 
    150. end 
    151. if MatTable(i)~=0 %表示找到增广路径了,此时起点肯定在匹配边上 
    152. EdgeNum=EdgeNum+1
    153. end 
    154. end 
    155. end 
    156.  
    157.  
    158. function testHungarian 
    159. c1=5
    160. c2=5
    161. % AdjMatrix=randi(2,c1,c2)-1; 
    162. t=0.7
    163. AdjMatrix=rand(c1,c2)>t; 
    164. % AdjMatrix=ones(c1,c2); 
    165. global AdjTable 
    166. AdjTable = cell(c1+c2,1); 
    167. for i=1:c1 
    168. t=find(AdjMatrix(i,:)~=0); 
    169. AdjTable{i}=c1+t; 
    170. end 
    171. for j=1:c2 
    172. t=find(AdjMatrix(:,j)~=0); 
    173. AdjTable{c1+j}=t; 
    174. end 
    175.  
    176. Hungarian(c1,'B',1); 
    177. end 
    178.  

    分析
    参考的blog中指出算法的时间复杂度为,实际应用中使用BFS的算法比DFS算法更快,但是在matlab代码中,发现使用DFS算法的搜索比BFS算法搜索的速度快不少,尤其是顶点和边数比较大的情形。


    参考文献
    Renfei Song's Blog
    百度百科-二分图

  • 相关阅读:
    学业优秀者汇总
    计算机类教学质量国家标准(含信息安全专业)
    从《构建之法》到《终身幼儿园》
    2019-2020-1 《信息安全专业导论》教学进程
    程序设计快速入门
    铜齿铁牙UP计划
    ios app 提交评审注意事项
    IOS开发之不同版本适配问题2(#ifdef __IPHONE_7_0)
    iOS:个性化UITextView(缩进,行距,铺满)
    iOS 同一设备内的应用之间资源共享的实现
  • 原文地址:https://www.cnblogs.com/YiXiaoZhou/p/5875040.html
Copyright © 2011-2022 走看看