Kuhn-Munkres算法(二分图最大权匹配)
这篇博客没有题,就是简单的说一下KM算法,今天花了两个小时学KM算法,总算明白了基本套路和基本原理,但是,有一个点从头到尾我都没有懂,lx[i]+ly[j]>weight[i][j]为什么是进入二分子图的条件,从百度上搜了也没有解释,GG了。还有就是这个式子求出来的值为何就是不合法匹配和合法匹配的最小差值,就这两个问题,一直搞不懂.....好迷啊。
其实KM算法可以用最小费用最大流来做,时间复杂度是一样的,就是KM算法比较好敲,换句话说,如果一个图可以构成二分图,就可以用KM算法和最小费用最大流两种方法来做,我这里放上两个大牛的讲解,一个讲解,一个代码。
http://blog.csdn.net/thundermrbird/article/details/52231639
http://blog.csdn.net/pi9nc/article/details/12250247
这两篇博客,仔细研究研究,建议先看讲解然后接着去看代码,马上就会明白这个算法是怎么回事。
放上我的代码,完全裸敲,以后当模板用。和大牛的一样
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#define inf 0x3f3f3f3f
using namespace std;
const int N=100;
int match[N];
int lx[N],ly[N];
int sx[N],sy[N];
int weight[N][N];
int n;
int dfs(int x){
sx[x]=true;
for(int i=0;i<n;i++){
if(!sy[i]&&lx[x]+ly[i]==weight[x][i]){
sy[i]=true;
if(match[i]==-1||dfs(match[i])){
match[i]=x;
return true;
}
}
}
return false;
}
int fax(int x){
if(!x){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
weight[i][j]=-weight[i][j];
}
}
}
memset(match,-1,sizeof(match));
for(int i=0;i<n;i++){
ly[i]=0;
lx[i]=-inf;
for(int j=0;j<n;j++){
if(weight[i][j]>lx[i]){
lx[i]=weight[i][j];
}
}
}
for(int i=0;i<n;i++){
while(1){
memset(sx,0,sizeof(sx));
memset(sy,0,sizeof(sy));
if(dfs(i))
break;
int mic=inf;
for(int j=0;j<n;j++){
if(sx[j]){
for(int k=0;k<n;k++){
if(!sy[k]&&lx[j]+ly[k]-weight[j][k]<mic){
mic=lx[j]+ly[k]-weight[j][k];
}
}
}
}
if(mic==0)
return -1;
for(int j=0;j<n;j++){
if(sx[j]){
lx[j]-=mic;
}
if(sy[j]){
ly[j]+=mic;
}
}
}
}
int sum=0;
for(int i=0;i<n;i++){
if(match[i]>=0){
sum+=weight[match[i]][i];
}
}
if(!x){
sum=-sum;
}
return sum;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&weight[i][j]);
}
}
int h=fax(1);
cout<<h<<endl;
return 0;
}
/*
5
3 4 6 4 9
6 4 5 3 8
7 5 3 4 2
6 3 2 2 5
8 4 5 4 7
*/
我就不讲这个代码了,讲的绝对没有大牛仔细啊