关闭

最小生成树-MST算法详解及代码实现

303人阅读 评论(0) 收藏 举报
分类:

from http://blog.csdn.net/coder_oyang/article/details/48195405

师兄发了一篇CCF-C类的文章,但是那个会议在澳洲排名属于B类,他说他在CVPR的某一篇文章的基础之上用了MST算法,避免了局部最优解,找到了全局最优解,实验结果比原文好很多,整个文章加实验前后仅仅做了2周。真是羡煞旁人也。。其实在机器学习当中,经常会遇到局部最优解的问题,所以,就花了点时间看看MST,兴许我也能找点灵感呢,呵呵..

看完最小生成树之后得到的一个想法就是:其实MST就是一种贪心算法,每一步选择都是选取当前候选中最优的一个选择。下面详细谈谈我认识的最小生成树吧

1. 最小生成树解决什么样的问题

城市之间建设道路的问题,首先,因为道路照价较高所以我们希望总的道路是最短的;其次,我们希望造的路在每个城市之间不会形成环路。那么MST的数学表达式就是这样,期望在图 G(V,E) 中找到一个子集 T 使得,使得造价函数w(T) 最小

2. MST 伪代码

在算法导论中对最小生成树的伪代码是这样描述的:

GENERIC(G,w){
A = empty
while A does not form a spanning tree
        find an edge (u,v) that is safe for A
        A = A & (u,v)
return A
}

算法的核心是在找到一条对于集合A安全的边。那么如何定义“安全”呢?

  • 安全边

先要定义一个名词:切割:无向图 G=(V,E) (V代表图中的结点,E代表图中两个节点之间的边) 的一个切割就是 (S , V-S) 就是集合V 的一个切割。

如上图就是图 G 的一个切割实例,如果图中的某一条边 (u,v) 的一个端点位于集合 S 中,另一个端点位于 V-S 中,那么这条边横跨切割 (S , V-S)。如果集合 A 中不存在这样的横跨边,那么该切割尊重集合 A 。在横跨一个切割的所有边中,权重最小的边称为轻量级边。上图中红色结点属于集合 S ,白色结点属于集合 V-S ,横跨改切割的边是那些连接红色与白色结点的边,边 (c,d) 是横跨改切割的唯一一条轻量级边。其中红色边属于子集 A :注意切割 (S , V-S) 尊重集合A,因为集合 A 中没有横跨改切割的边。那么安全边的定于有如下定义
设G=(V , E) 是一个在边E上定义了实数权值函数 w 的的连通无向图。设集合 A 为 E 的一个子集,且 A 包括在图G的某棵最小生成树中,设 (S , V-S) 是图G中尊重集合A的任意一个切割,又设 (u,v) 是横跨切割 (S,V-S) 的一条轻量级边。那么边 (u,v) 对于集合 A 是安全的。

3. MST实现算法:Kruskal \ Prim

前文分析了MST算法核心:如何寻找安全边。这里有两种经典算法,一是Kruskal 算法,另一个是Prim算法,先来看看Kruskal 算法是如何找安全边的。

3.1 Kruskal 算法

Kruskal 算法找到安全边的想法在所有连接森林中两棵不同树的边里面,找到权重最小的边 (u,v) 。假设C1和C2为边 (u,v) 所连接的两棵树。由于边 (u,v) 一定是连接C1和其他某棵树的一条轻量级边,那么 (u,v) 一定是条安全边。

MST-KRUSKAL(G,w){
    A= NULL
    for each vector v in G.V
         MAKE-SET(v)
    sort the edges of G.E into nondecreasing order by weight w
    for each edge(u,v) in G.E, taken in nondecreasing order by weight
         if FIND-SET(v) != FIND-SET(u)
            A = A & {(u,v)}
            UNION(u,v)
    return A
}

说明:FIND-SET(v) != FIND-SET(u) 判断结点 u , v 是否属于同一棵树,下面是执行Kruskal算法的过程,红色的边属于不断增长的森林A。该算法按照边的权值大小一次进行考虑,箭头所指的边是算法每一步所考察的边。如果该条边将两棵不同的树连接起来,它就被加入到森林里面去,从而完成对两棵树的合并。

总结Kruskal 算法:1: 连接的是两颗不同的树   2:选取的是轻量级边   循着这两个条件便实现Kruskal 算法

算法代码见 算法导论 19-2 采用二项堆的最小生成树算法

3.2 Prim 算法

Prim算法所具有的一个性质是集合 A 中的边总是构成一棵树。从任意的根结点出发,一直长大到覆盖 V 中的所有结点为止。算法每一步在连接集合A与A之外的结点的所有边中,选择一条轻量级边加入到 A 中,下面是执行Prim算法的过程

其中红色边与结点都属于树A。在每一步算法中,树的结点就决定了图的一个切割,横跨该切割的一条轻量级边被加入到树中。


参考文献

算法导论 Thomas H. et.al


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:11746次
    • 积分:177
    • 等级:
    • 排名:千里之外
    • 原创:1篇
    • 转载:29篇
    • 译文:0篇
    • 评论:1条
    文章存档
    最新评论