非递归版本KM算法学习笔记

原创 2016年08月29日 00:39:34

KM算法的思想在于,如最大权匹配,给出一个二分图,在左右两边的点上都记一个顶标,左边Ai,右边Bi,时刻保证Ai+BIWi,j,当增广路算法结束之后,我们可以通过修改顶标来增大相等子图,这个修改值就是min(Wi,jAiBi)
代码:

namespace KM{
    #define N 410
    int n;
    int A[N], B[N];
    int w[N][N];
    int link[N], ans[N];
    bool vis[N], vis1[N];
    int mn; 

    inline void init(){
        memset(w, 0, sizeof(w));
    }

    inline bool find(int x){
        vis[x] = true;
        for(int i = 1; i <= n; i ++){
            if(vis1[i]) continue;
            //if(!w[x][i]) continue;
            int t = A[x] + B[i] - w[x][i];
            if(!t){
                vis1[i] = true; 
                if(!~link[i] || find(link[i])){
                    link[i] = x;
                    ans[x] = i;
                    return true;
                }
            }
            else mn = min(mn, t);
        }
        return false;
    }

    inline void km(){
        memset(link, -1, sizeof(link));
        memset(A, 0, sizeof(A));
        memset(B, 0, sizeof(B));
        for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= n; j ++){
                A[i] = max(A[i], w[i][j]);
            }
        }
        for(int i = 1; i <= n; i ++){
            while(1){
                memset(vis, 0, sizeof(vis));
                memset(vis1, 0, sizeof(vis1));
                mn = inf;
                if(find(i)) break;
                for(int j = 1; j <= n; j ++){
                    if(vis[j]) A[j] -= mn;
                    if(vis1[j]) B[j] += mn; 
                }
            }
        }
    }

    inline int getsum(){
        int ret = 0;
        for(int i = 1; i <= n; i ++) ret += A[i], ret += B[i];
        return ret;
    }
} 

最小权匹配同理。
非递归的KM算法,通过bfs,记录一个slack数组,每次我们可以用slack数组来维护这个修改值,也就是利用广搜的思想,即可

int n;
int A[M], B[M], lk[M], way[M], mn[M];
int w[M][M];
bool vis[M];

inline void km(int x){
    lk[0] = x;
    int j0 = 0;
    memset(vis, 0, sizeof(vis));
    memset(mn, 0x3f, sizeof(mn));
    do{
        vis[j0] = true;
        int i0 = lk[j0], num = inf, j1;
        for(int j = 1; j <= n; j ++){
            if(!vis[j]){
                int t = A[i0] + B[j] - w[i0][j];
                if(t < mn[j]) mn[j] = t, way[j] = j0;
                if(mn[j] < num) num = mn[j], j1 = j;
            }
        }
        for(int j = 0; j <= n; j ++){
            if(vis[j]) A[lk[j]] -= num, B[j] += num;
            else mn[j] -= num;
        } 
        j0 = j1;
    } while(~lk[j0]);
    do{
        int j1 = way[j0];
        lk[j0] = lk[j1];
        j0 = j1;
    } while(j0);
}

这个代码是做一次增广路的代码,外面套一层for(inti=1;i<=n;i++)即可,另外这个顶标初始值不必设成最大值,因为有mn数组。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

二叉树插入算法的非递归版本

首先约定结点和元素类型的的定义:typedef int ElementType; typedef struct TNode *Position; typedef Position BinTree; s...

数据结构学习笔记1-链表反转(递归与非递归)

最近在学习数据结构,做下笔记:

数据结构与算法分析笔记与总结(java实现)--二叉树2:非递归二叉树的序列打印练习题

数据结构与算法分析笔记与总结(java实现)--二叉树2:非递归二叉树的序列打印练习题

经典算法学习——非递归遍历二叉树

我们知道二叉树是一种递归定义的数据结构,包括二叉树的创建、遍历、求树高、叶子节点个数等等。使用递归来进行以上操作非常的简便,相关实现请参考 《C语言实现二叉树的基本操作》。但是今天我们剑走偏锋,使用非...

学习笔记----KM算法

话说KM这个东西看起来有点吃力啊,本来就笨再加上状态不是很好,看的好慢啊。一开始看的书,书上有好多的什么定理的东东说的很官方,不是那么的通俗易懂啊。 我自己的理解就是在二分图中找一个最优的匹配。意思就...

算法学习 - 表达树的建立(后缀表达式法),树的先序遍历,中序遍历,后序遍历(非递归)

表达树就是根据后缀表达式来建立一个二叉树。 这个二叉树的每个叶子节点就是数,真祖先都是操作符。 通过栈来建立的,所以这里也会有很多栈的操作。 树的先序遍历,中序遍历,后序遍历的概念我就不讲了,不会的自...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)