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.