匈牙利算法的C++实现(基于OpenCV)


    Hungarian/Munkres Algorithm,即著名的匈牙利算法,常用来解决矩形分配问题:我有一些工作jobs,也有一些工人workers,我已经知道每个worker做各个job的耗费cost,那么我如何将各个job分配给各个worker才能使得总的cost最小呢??这就是匈牙利算法干的事情,他起初是用来解决workers和jobs个数一样多的情形,后来发展成能解决不等量worker-job分配问题。看看这个网页相信能给你一个对Hungarian算法的基本的了解:HungarianAlgorithm.com

    实话说,我自己对匈牙利算法的原理了解不多,但是因为需要用到它,我就稍微查了点资料,比如咱们csdn上有相关博客,在matlab的文件中心搜一下关键词Hungarian能找到许多代码,因为急用,我翻写了其中一篇matlab代码,一个月来,使用情况较为满意,下面把代码贴出来与大家分享。

//文件munkres.cpp
#include "cv.h"
using namespace cv;
using namespace std;


// B = A( extractRows, extractCols )
// Require: 
//	extractRows.size()==A.rows, extractCols.size()==A.cols
//	sum(extractRows)==B.rows, sum(extractCols)==B.cols
void  extractGrids( const Mat &A, const vector &extractRows, const vector &extractCols, Mat &B )
{
	typedef float ValueType;
	ValueType *pt1 = (ValueType*)A.data, *pt2 = (ValueType*)B.data, *pt3, *pt4;
	const int step1 = A.step1(), rows = A.rows, cols = A.cols, step2 = B.step1();
	vector::const_iterator it1, it2, it3 = extractRows.end(), it4 = extractCols.end();
	for( it1=extractRows.begin(); it1!=it3; pt1+=step1 ){
		pt3 = pt1;
		if( *(it1++) ){
			pt4 = pt2;
			for( it2=extractCols.begin(); it2!=it4; pt3++ )
				if( *(it2++) )
					*(pt4++) = *pt3;
			pt2 += step2;
		}
	}
}

// B = A( extract )
// Require: 
//		min(A.rows,A.cols) ==1
//		if(A.rows)==1, then require: A.cols==extract.size(), B.rows==1, sum(extract)==B.cols
//		if(A.cols)==1, then require: A.rows==extract.size(), B.cols==1, sum(extract)==B.rows
void  extractDots( const Mat &A, const vector &extract, Mat &B )
{
	assert( A.rows==1 || A.cols==1 );
	typedef float ValueType;
	ValueType *pt1 = (ValueType*)A.data, *pt2 = (ValueType*)B.data;
	vector::const_iterator it = extract.begin(), it2 = extract.end();
	if( A.rows==1 ){
		for( ; it!=it2; pt1++ )
			if( *(it++) )
				*(pt2++) = *pt1;
	}
	else{
		int step1 = A.step1(), step2 = B.step1();
		for( ; it!=it2; pt1+=step1 )
			if( *(it++) ){
				*pt2 = *pt1;
				pt2+=step2;
			}
	}
}


/* Initial Matlab code comes from: 
	http://www.mathworks.com/matlabcentral/fileexchange/20652-hungarian-algorithm-for-linear-assignment-problems--v2-3-
	
	Hungarian algorithm for matrix assignment problem.
	costMat: there are (rows) works and (cols) jobs. costMat(i,j) means the cost of assigning job (j) to worker (i).
	The problem is to solve a holistic optimization problem of assigning each worker a job!
	The algorithm allows partial assignment - if there is no proper job for worker (i) we would set assignment(i) to -1, meaning no assignment for worker (i).

	Negatives in costMat means the corresponding assignments are forbidden.
*/
void  munkres( Mat &costMat, vector &assignment )
{
	assert( costMat.type()==CV_32FC1 );
	const int rows = costMat.rows, cols = costMat.cols;
	assignment.assign( rows, -1 );

	Mat validMat( rows, cols, CV_8UC1 );
	compare( costMat, Scalar(0), validMat, CV_CMP_GE );

	float *ptF, *ptF2;
	uchar *ptU, *ptU2;
	int stepGap;
	int r, c, i;
	unsigned j;
	vector::iterator it1, it2;
	vector::iterator it3, it4;

	// validCol & validRow	
	vector validRow( rows, false );
	ptU = validMat.data;
	for( r=0; r validCol( cols, false );
	ptU = validMat.data;	
	for( c=0; cnCols ? nRows : nCols;
	if( !n )
		return;

	// sumValid & maxValid
	float sumValid = 0, maxValid = -1.f;
	ptF = (float*)costMat.data;
	ptU = validMat.data;
	stepGap = validMat.step - validMat.cols;	
	r = 0; while(r++maxValid ) maxValid = v;
			}
			else ptF++;
		} ptU += stepGap;
	}

	// bigM & maxValid	
	maxValid *= 10.f;
	float bigM = log10f( sumValid );
	int power = (int)ceilf( bigM ) + 1;	
	bigM = 1.f; //bigM = pow( 10, power );
	for( i=0; i starZ(n,-1);
	ptU = zP.data;
	for( r=0; r noncoverColumn( n, true );
		for( it3=starZ.begin(); it3!=starZ.end(); it3++ ){ 
			if( *it3<0 ) continue;
			noncoverColumn[*it3] = false;
		}
		vector noncoverRow( n, true );
		vector primeZ(n,-1);

		// minC_uncovered & minR_uncovered
		int cnt1 = 0, cnt2 = 0;
		it1 = noncoverColumn.begin(), it2 = noncoverRow.begin();
		i = 0; while(i++ rIdx, cIdx; // [rIdx,cIdx] = find(temp4);
		ptU = temp4.data;
		stepGap = temp4.step - temp4.cols;
		for( r=0; r cR, cC;
			for( j=0; j rIdx2, cIdx2;
				for( it3=rIdx.begin(), it4=cIdx.begin(); it3!=rIdx.end(); it3++, it4++ )
					if( *it3!=uZr ){
						rIdx2.push_back( *it3 );
						cIdx2.push_back( *it4 );
					}
				rIdx = rIdx2, cIdx = cIdx2;
				// cR = find(~coverRow);
				cR.clear();
				for( j=0; j(stz) );
				temp1 = tmp1( cv::Rect(0,0,1,sz) );
				extractDots( dMat.col(stz), noncoverRow, temp1 );
				temp4 = tmp4( cv::Rect(0,0,1,sz) );
				compare( temp1, minR_uncovered, temp4, CV_CMP_EQ );
				// rIdx = [rIdx(:);cR(z)];
				for( i=0, ptU=temp4.data; i=0 ){
			starZ[rowZ1] = -1;
			uZc = primeZ[rowZ1];
			uZr = rowZ1;
			for( j=0; j rowIdx( nRows ), colIdx( nCols );
	it1=validRow.begin(), it2=validCol.begin();
	for( i=0, it3=rowIdx.begin(); i vIdx( nRows, false );
	it1=vIdx.begin(), it3=starZ.begin();
	i = 0; while(i++-1 ){
			uchar isInvalid = validMat.at( j, job ); // validMat is now "invalidMat"
			if( isInvalid )
				assignment[j] = -1;
		}
	}
}

参考文献:

[1] The Hungarian Method for The Assignment Problem. chapter 2 of the book "50 Years of Integer Programming 1958-2008" by M.Junger, T.Liebling, et al. Springer print.

[2] The Assignment Problem and The Hungarian Method.

你可能感兴趣的:(C++实现,匈牙利算法,匈牙利算法,Hungarian,algorithm,Munkres,algorithm,C++源码下载)