无向图最小生成树Kruskal算法

问题

最小生成树的Kruskal算法

描述:有A、B、C、D四个点,每两个点之间的距离(无方向)是(第一个数字是两点之间距离,后面两个字母代表两个点):(1,‘A‘,‘B‘),(5,‘A‘,‘C‘),(3,‘A‘,‘D‘),(4,‘B‘,‘C‘),(2,‘B‘,‘D‘),(1,‘C‘,‘D‘) 生成边长和最小的树,也就是找出一种连接方法,将各点连接起来,并且各点之间的距离和最小。

思路说明:

Kruskal算法是经典的无向图最小生成树解决方法。此处列举两种python的实现方法。这两种方法均参考网上,并根据所学感受进行了适当改动。

解决1(Python)

#! /usr/bin/env python
#coding:utf-8

#以全局变量X定义节点集合,即类似{'A':'A','B':'B','C':'C','D':'D'},
#如果A、B两点联通,则会更改为{'A':'B','B':'B",...},即任何两点联通之后,两点的值value将相同。

X = dict()      

#各点的初始等级均为0,如果被做为连接的的末端,则增加1

R = dict()

#设置X R的初始值

def make_set(point):
    X[point] = point
    R[point] = 0

#节点的联通分量

def find(point):
    if X[point] != point:
        X[point] = find(X[point])
    return X[point]

#连接两个分量(节点)

def merge(point1,point2):
    r1 = find(point1)
    r2 = find(point2)
    if r1 != r2:
        if R[r1] > R[r2]:
            X[r2] = r1
        else:
            X[r1] = r2
            if R[r1] == R[r2]: R[r2] += 1

#KRUSKAL算法实现

def kruskal(graph):
    for vertice in graph['vertices']:
        make_set(vertice)

    minu_tree = set()

    edges = list(graph['edges'])
    edges.sort()                    #按照边长从小到达排序
    for edge in edges:
        weight, vertice1, vertice2 = edge
        if find(vertice1) != find(vertice2):
            merge(vertice1, vertice2)
            minu_tree.add(edge)
    return minu_tree

if __name__=="__main__":

    graph = {
        'vertices': ['A', 'B', 'C', 'D', 'E', 'F'],
        'edges': set([
            (1, 'A', 'B'),
            (5, 'A', 'C'),
            (3, 'A', 'D'),
            (4, 'B', 'C'),
            (2, 'B', 'D'),
            (1, 'C', 'D'),
            ])
        }

    result = kruskal(graph)
    print result

解决2(Python)

#! /usr/bin/env python
#coding:utf-8

class UnionFind:

    def __init__(self):

        self.weights = {}
        self.parents = {}

    def __getitem__(self, object):

        if object not in self.parents:
            self.parents[object] = object
            self.weights[object] = 1
            return object

        path = [object]
        root = self.parents[object]
        while root != path[-1]:
            path.append(root)
            root = self.parents[root]

        for ancestor in path:
            self.parents[ancestor] = root
        return root

    def __iter__(self):

        return iter(self.parents)

    def union(self, *objects):

        roots = [self[x] for x in objects]
        heaviest = max([(self.weights[r],r) for r in roots])[1]
        for r in roots:
            if r != heaviest:
                self.weights[heaviest] += self.weights[r]
                self.parents[r] = heaviest

#判断是否是无向图
def isUndirected(G):

    for v in G:
        if v in G[v]:
            return False
        for w in G[v]:
            if v not in G[w]:
                return False
    return True

#最小生成树

import unittest

def MinimumSpanningTree(G):

    if not isUndirected(G):
        raise ValueError("MinimumSpanningTree: input is not undirected")
    for u in G:
        for v in G[u]:
            if G[u][v] != G[v][u]:
                raise ValueError("MinimumSpanningTree: asymmetric weights")

    subtrees = UnionFind()
    tree = []
    for W,u,v in sorted((G[u][v],u,v) for u in G for v in G[u]):
        if subtrees[u] != subtrees[v]:
            tree.append((u,v))
            subtrees.union(u,v)
    return tree        

#单元测试

class MSTTest(unittest.TestCase):
    def testMST(self):

        G = {0:{1:11,2:13,3:12},1:{0:11,3:14},2:{0:13,3:10},3:{0:12,1:14,2:10}}
        T = [(2,3),(0,1),(0,3)]
        for e,f in zip(MinimumSpanningTree(G),T):
            self.assertEqual(min(e),min(f))
            self.assertEqual(max(e),max(f))

if __name__ == "__main__":
    unittest.main()   

参考资料

1.《算法基础》(GILLES Brassard,Paul Bratley)

2.http://www.ics.uci.edu/~eppstein/PADS/

更多相关代码,请访问:https://github.com/qiwsir/algorithm

无向图最小生成树Kruskal算法

时间: 2025-01-10 16:54:04

无向图最小生成树Kruskal算法的相关文章

SOJ4339 Driving Range 最小生成树 kruskal算法

典型的最小生成树 然后求最大的一条边 附上链接 http://cstest.scu.edu.cn/soj/problem.action?id=4339 需要注意的是有可能有 "IMPOSSIBLE" 的情况 这里用一个flag标记 记录所并的节点 只有flag = n时才能成功 负责就 "IMPOSSIBLE" 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring&g

最小生成树 kruskal算法简介

生成树--在一个图中的一个联通子图  使得所有的节点都被(访问) 最小生成树 (MST) 即联通子图的总代价(路程)最小 已知的一个图 有n个点 m条边 kruskal的算法如下 先对边从小到大排序 从最小的边起,不停的合并这条边的两个节点到一个集合,如果这条边的两个节点已经在一个集合里,则无视,否则形成回路(显然错误)直到所有的节点并到一个集合里 这里需要用到并查集来合并节点 1 int cmp(const int i,const int j) { 2 return w[i] < w[j];

最小生成树 Kruskal算法

Kruskal算法 1.概览 Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表.用来解决同样问题的还有Prim算法和Boruvka算法等.三种算法都是贪婪算法的应用.和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效. 2.算法简单描述 1).记Graph中有v个顶点,e个边 2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边 3).将原图Graph中所有e个边按权值从小到大排序 4)

无向图最小生成树Prim算法

问题 无向图最小生成树的Prim算法.一般的实现过程,采用了常规排序.本文在用Python实现中,使用了python的堆排序模块,不仅精简代码,而且提高效率. 思路说明 假设点A,B,C,D,E,F,两点之间有连线的,以及它们的距离分别是:(A-B:7);(A-D:5);(B-C:8);(B-D:9);(B-E:7);(C-E:5);(D-E:15);(D-F:6);(E-F:8);(E-G:9);(F-G:11) 关于Prim算法的计算过程,参与维基百科的词条:[普里姆算法] 将上述点与点关系

最小生成树Kruskal算法的提出者Joseph Bernard Kruskal,Jr.

熟悉算法中的最小生成树的朋友都晓得有一个Kruskal算法,这个算法就是由题目中那个名字很长的人提出的.因为他功绩卓越,尊称他为Kruskal. Kruskal生于1928年1月29日,卒于2010年9月19日,美国人,维基里的词条中包含的头衔是:数学家.统计学家.计算机科学家.心理测量学专家. kruskal分别就读过芝加哥大学和普林斯顿大学,1954年获得博士学位. 下面链接中是一篇几年他的文章,从中可以了解他的更多成就.顺便说一句,他的父母和兄弟也都很牛. http://pan.baidu

ZOJ 1718 POJ 2031 Building a Space Station 修建空间站 最小生成树 Kruskal算法

题目链接:ZOJ 1718 POJ 2031 Building a Space Station 修建空间站 Building a Space Station Time Limit: 2 Seconds      Memory Limit: 65536 KB You are a member of the space station engineering team, and are assigned a task in the construction process of the statio

最小生成树——Kruskal算法

前面介绍了最小生成树和Prim算法,这篇博客继续记录Kruskal算法的相关内容. 算法思想: 1. 先将所有边按权值由小到大排序: 2. 从边集中选出第一条边(即权值最小的边),如果与树中现有的边不构成环,则将其加入树中: 3. 重复步骤2直至树中有n-1条边. 在实现上述算法之前,要先解决三个问题: 1. 如何表示一条边? 虽然我们尽量简化情景方便实现,但是边还是不能像节点一样简单地用一个数表示,因为它有三个必备的属性:起点.终点和权值.因此,我们创建以下结构体来表示边: 1 // 定义表示

最小生成树Kruskal算法

Kruskal算法就是把图中的所有边权值排序,然后从最小的边权值开始查找,连接图中的点,当该边的权值较小,但是连接在途中后会形成回路时就舍弃该边,寻找下一边,以此类推,假设有n个点,则只需要查找n-1条边即可. #include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; const int maxn=1000; int v,l

并查集扩展之最小生成树Kruskal算法

并查集有很多经典的应用.在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中. 其中一个非常经典的应用是最小生成树的Kruskal算法.给定一个具有n个节点的连通图,它的生成树是原图的一个子图,包含所有n个节点,且有保持图连通的最少的边(n-1条边).边权值最小的生成树是最小生成树. kruskal算法是一个贪心算法,把所有的边按权值从小到大依次考虑,如果当前边加进生成树中会出现回路