Kuhn-Munkres算法(二分图最大权匹配)

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
*/
我就不讲这个代码了,讲的绝对没有大牛仔细啊

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值