算法应用场景:
农夫约翰上个星期刚刚建好了他的新牛棚,他使用了最新的挤奶技术。不幸的是,由于工程问题,每个牛栏都不一样。第一个星期,农夫约翰随便地让奶牛们进入牛栏,但是问题很快地显露出来:每头奶牛都只愿意在她们喜欢的那些牛栏中产奶。上个星期,农夫约翰刚刚收集到了奶牛们的爱好的信息(每头奶牛喜欢在哪些牛栏产奶)。一个牛栏只能容纳一头奶牛,当然,一头奶牛只能在一个牛栏中产奶。问如何匹配奶牛与牛栏以便产奶最大化。
有关匈牙利算法的原理讲解可参考
http://imlazy.ycool.com/post.1603708.html,作者通过图形的方式讲解的很详细
匈牙利算法最主要的环节是搜寻增广路径(augmentPath)的过程,假设有两个2分图X和Y,增广路径的搜寻逻辑大致如下:
成员变量定义
匹配集合:M
增广路径中边的集合:path
方法定义:
boolean hasAugmentPath(X x);//判断x是否有增广路径
伪代码描述:
1.for(y:x.getY())//遍历x对应的Y
1.1(x,y)在匹配集合M里
1.1.1 x只对应一个y(即x.getY().size==0) ->return false;//顶点x没有增广路径
1.1.2 x还有其他对应的y ->continue 1
1.2(x,y)不在匹配集合里 ->path集合添加(x,y)这条边
1.2.1 y没有被使用 ->reture true;//找到增广路径
1.2.2 y已经被使用了 ->for(x1:y.getX())//遍历y对应的x
1.2.2.1(y,x1)在path里
1.2.2.1.1 y只有一个x1 ->return false
1.2.2.1.1 y还有其他x1 ->continue 1.2.2
1.2.2.2(y,x1)在匹配集合里 ->path集合添加(y,x1)这条边
递归跳转到1,判断x1是否有增广路径
1.2.2.1 x1有增广路径 ->return true
1.2.2.2 x1没有增广路径 ->path集合中移除(y,x1) continue 1.2.2
1.2.2.3(y,x1)不在匹配集合里 ->continue 1.2.2
1.2.3遍历步骤1.2.2结束依然没有找到增广路径 ->path集合移除(x,y)这条边 continue 1
2.遍历步骤1中所有y依然没有找到增广路径 ->return false//断定x没有增广路径
获取到增广路径之后,需要重新计算匹配集合,方法是将path和M两个集合进行合并,并去掉集合的交集
如path={A,B,C},M={B,C,D}则重新计算出的匹配集合为{A,D}
遍历X中所有的顶点,最终得到的匹配集合就是算法需要的结果
java代码实现:
DateSource类用于封装测试数据源,包括两种,分别是DataSource和DateSource2,两种数据源对应的图形如图所示
Cow类用于封装奶牛信息
Kraal用于封装牛栏信息
Match用于封装奶牛和牛栏的匹配信息
Hungary用于处理匈牙利算法的具体逻辑
Main类用于算法测试
代码可点击URL下载
http://download.csdn.net/detail/javaman_chen/4852597
数据源1测试结果如下:
最大匹配数:3
匹配信息:[D->1, C->3, B->2]
数据源2测试结果如下:
最大匹配数:4
匹配信息:[D->2, B->1, A->3, C->4]