利用Kuhn-Munkras算法求最小权值匹配

本文参考博客:
http://blog.csdn.net/zhangpinghao/article/details/12242823(代码参考该博客)
http://philoscience.iteye.com/blog/1754498(个人认为对km算法讲解比较好)

KM算法求的是基于带权二分图中完备匹配下的最大权值匹配。关于km算法的讲解网上资料比较丰富,此处就不详述啦。这里主要整理一些用KM算法求最小权值匹配的一些问题。

  • 在求最大权值匹配时,不存在的边的权值设为0。在求最小权值匹配时,可以考虑将对应的权值变为相反数,或者用一个很大的数减去权值,然后再来求最大权值匹配,最后将权值和取反即可。如果使用将对应的权值变为相反数的方法,则不存在的边的权值此时要设为INT_MAX(即,实际中求匹配时使用的是-INT_MAX),如此设置之后还需要特别注意溢出的问题, if( !sy[j] && ((lx[i] + ly[j] - weight[i][j] ) 这一句对于带符号整型数可能会溢出,所以此句可以改成if( !sy[j] && weight[i][j]!=-INT_MAX && ((lx[i] + ly[j] - weight[i][j] ),即不予考虑不存在的边。

  • 注意,km算法求的是完备匹配,即x集中的点数m与y集中的点数n不一定相同,但m<=n,最终结果是给x集合中的每一个值都找到一个y中的匹配。

  • 如果一个y集合中的点最多可以对应n个x集合中的点,则可以将y中的点数拓展n倍,最后变成一一对应的关系。

#include   
#include   
#include   
#include    
#include 

using namespace std;  
      
#define MAX 100  
      
int m,n;	//x集与y集的点数
int weight[MAX][MAX];           //边的权重  
int lx[MAX],ly[MAX];            //期望值,定点标号  
bool sx[MAX],sy[MAX];           //记录寻找增广路时点集x,y里的点是否搜索过  
int match[MAX];                 //match[i]记录y[i]与x[match[i]]相对应  
      
bool search_path(int u) {          //给x[u]找匹配,这个过程和匈牙利匹配是一样的  
	int v;
	sx[u]=true;		  
	for(v=0; v=0)  
			sum+=weight[match[i]][i];  
      
	if(!max_weight)  
		sum=-sum;  
	return sum;  
      
}


int main(){  
    int i,j;
	printf("请输入X集与Y集的点数:M,N\n");
	scanf("%d%d",&m,&n);  
	printf("请输入权重\n");
	for(i=0;i

一些重要概念的补充:

  • 二分图:顶点分为两个集合X和Y,所有的边关联在两个顶点中,恰好一个属于集合X,另一个属于集合Y。
  • 最大匹配:图中包含边数最多的匹配称为图的最大匹配。(这个时候不涉及权值)
  • 完备匹配与完美匹配:G=< V1, V2, E >,|V1|<=|V2|,M为G中的一个最大匹配,且|M|=|V1|,则称M为V1到V2的完备匹配,若|V2|=|V1|,则完备匹配即为完美匹配,若|V1|<|V2|,则完备匹配为G中的最大匹配。
  • 匈牙利算法:用增广路求二分图的最大匹配。
  • KM算法:利用匈牙利算法求完备匹配下的最大权重匹配。

你可能感兴趣的:(数据结构与算法)