Ek算法浅析(带权二分图)

https://www.cnblogs.com/logosG/p/logos.html

https://blog.csdn.net/chenshibo17/article/details/79933191

HDU 2255

/*
 * @Author: CY__HHH
 * @Date: 2019-10-23 20:09:44
 * @LastEditTime: 2019-10-24 16:41:12
 */
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstring>
#define inf (0x3f3f3f3f)
const int maxn = 305;
int Grape[maxn][maxn];
int exp_girl[maxn];
int exp_boys[maxn];
bool vis_girl[maxn],vis_boys[maxn];
int match[maxn],minExp[maxn],n;
using namespace std;
bool find(int u)
{
    vis_girl[u] = true;
    for(int v=0;v!=n;++v)
    {
        if(vis_boys[v])
            continue;//只能匹配一次
        int value = exp_girl[u] + exp_boys[v] - Grape[u][v];
        if(!value)//符合要求
        {
            vis_boys[v] = true;//路径
            if(match[v]==-1||find(match[v]))
            {
                match[v] = u;
                return true;
            }
        }else{
            minExp[v] = min(minExp[v],value);//得到路径中的左边节点的min
        }
    }
    return false;
}
int KM()
{
    memset(match,-1,sizeof(match));
    memset(exp_boys,0,sizeof(exp_boys));
    for(int v=0;v!=n;++v)
    {
        exp_girl[v] = Grape[v][0];
        for(int i=1;i!=n;++i)
            exp_girl[v] = max(exp_girl[v],Grape[v][i]);
    }//最大期望值
    for(int v=0;v!=n;++v)//为每个girl节点
    {
        memset(minExp,inf,sizeof(minExp));//减少最少权值能够增加边(增广路)
        while(true)//如果找不到,就降低权值
        {
            memset(vis_girl,false,sizeof(vis_girl));
            memset(vis_boys,false,sizeof(vis_boys));//记录路径
            if(find(v))
                break;//如果找到匹配
            int mind = inf;
            //因为现存的路径中无法满足匹配,所以需要从非路径中节点挑选一个减少最小的来完成(增加边)
            for(int i=0;i!=n;++i)
                if(!vis_boys[i])
                    mind = min(mind,minExp[i]);
            for(int i=0;i!=n;++i)
            {
                if(vis_girl[i])
                    exp_girl[i] -= mind;
                if(vis_boys[i])
                    exp_boys[i] += mind;
                else
                    minExp[i] -= mind;
            }
        }
    }
    int cnt = 0;
    for(int i=0;i!=n;++i)
        cnt += Grape[match[i]][i];
    return cnt;
}
int main()
{
    while(scanf("%d",&n)==1)
    {
        for(int i=0;i!=n;++i)
            for(int j=0;j!=n;++j)
                scanf("%d",&Grape[i][j]);
        printf("%d\n",KM());
    }
}

  

posted on 2019-10-24 16:48  chengyulala  阅读(209)  评论(0编辑  收藏  举报

导航