soj1303 KM算法

这是一道典型应用KM算法的二分带权图最大匹配问题,第一次学习KM算法,有许多不懂得地方,参考了博客http://www.cnblogs.com/wenruo/p/5264235.html的详解,稍微懂了一点,把源代码翻译成了伪代码,如下

Algorithm KM(map[][], n)
    Input: map[][], a two dimension array that records the power of the edge in a bipartite graph.
          n, an integer, the size of the array
    Output: The sum of the power of the greatest bipartite graph matching

Global variable
    int ex_x[maxn]     // x的期望值
    int ex_y[maxn]     // y的期望值
    bool vis_x[maxn]   // 每一轮匹配过的x集合
    bool vis_y[maxn]   // 每一轮匹配过的y集合
    int match[maxn]    // 当前y匹配到的x
    int slack[maxn]    // y被匹配最少再需期望

DFS(int x)
    vis_x[x] = true
    for y = 0 to N-1
        if vis_y[y] then continue
        gap = ex_x[x] + ex_y[y] – map[x][y]
        if gap == 0 then
            vis_y[y] = true
            // 找到一个适合的y后,y还没被匹配,或y的原配能再找到匹配
            if match[y] == -1 || DFS(match[y]) then
                match[y] = x
                return true
        else slack[y] = min(slack[y], gap) // 不适合,y更新slack
    return false

KM()
    set(match, -1)     // x=match[y],初始化为-1,为匹配状态
    set(ex_y, 0)       // y的期望初始化为0
    // 对每个x0找到对应最大的map[x0][y],此步为贪心
    for i = 0 to N-1
        ex_x[i] = map[i][0]
        for j = 0 to N-1
            ex_x[i] = max(ex_x[i], map[i][j])
    // 遍历每个x,去匹配一个y
    for i = 0 to N-1
        set(slack, INF)   // 最少再需期望用到min,初始化为INF
        while true
            set(vis_x, false)  // 重置已访问集合,下同
            set(vis_y, false)
            // 找到匹配,退出while
            if DFS(i) then break  
            // 没有找到匹配,降低x期望,升高y期望
            d = INF      // d为最小可降低期望
            for j = 0 to N-1
                if !vis_y[j] then d = min(d, slack[j])
            for j = 0 to N-1
                if vis_x[j] then ex_x[j] -= d
                if vis_y[j] then ex_y[j] += d
                else slack[j] -= d
    res = 0 
    for i = 0 to N-1
        res += map[ match[i] ][i]
    return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值