无向图最小生成树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算法的计算过程,参与维基百科的词条:[普里姆算法]

将上述点与点关系以及两点之间距离(边长,有的文献中称之为权重)写成矩阵形式(在list中,每两个点及其之间的距离组成一个tuple)

edges = [ ("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)

]

在下面的解决方法中,要计算出与已经选出的若干个点有相邻关系的点中,相应边长最短的点。这本质上是排序之后取出最小的,因为这种排序是动态的,如果用sorted或者list.sort()之类的方法对list排序,一则速度慢(python中的sort方法对大数据时不是很快),二则代码也长了。幸好python提供了一个非常好用的模块:heapq。这个模块是堆排序方法实现排序,并能够随时取出最小值。简化代码,更重要是提升了速度。

就用这个来解决Prim算法问题了。

解决(Python)

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

    from collections import defaultdict
    from heapq import *

    def prim( vertexs, edges ):
        adjacent_vertex = defaultdict(list)      

        for v1,v2,length in edges:
            adjacent_vertex[v1].append((length, v1, v2))
            adjacent_vertex[v2].append((length, v2, v1))

        """
        经过上述操作,将edges列表中各项归类成以某点为dictionary的key,其value则是其相邻的点以及边长。如下:

        defaultdict(<type 'list'>, {'A': [(7, 'A', 'B'), (5, 'A', 'D')],
                                    'C': [(8, 'C', 'B'), (5, 'C', 'E')],
                                    'B': [(7, 'B', 'A'), (8, 'B', 'C'), (9, 'B', 'D'), (7, 'B', 'E')],
                                    'E': [(7, 'E', 'B'), (5, 'E', 'C'), (15, 'E', 'D'), (8, 'E', 'F'), (9, 'E', 'G')],
                                    'D': [(5, 'D', 'A'), (9, 'D', 'B'), (15, 'D', 'E'), (6, 'D', 'F')],
                                    'G': [(9, 'G', 'E'), (11, 'G', 'F')],
                                    'F': [(6, 'F', 'D'), (8, 'F', 'E'), (11, 'F', 'G')]})

        """

        mst = []        #存储最小生成树结果

        chosed = set(vertexs[0])

        """
        vertexs是顶点列表,vertexs = list("ABCDEFG")===>vertexs=['A', 'B', 'C', 'D', 'E', 'F', 'G']
        >> chosed=set(vertexs[0])
        >> chosed
        set(['A'])
        也就是,首先选一个点(这个点是可以任意选的),以这个点为起点,找其相邻点,以及最短边长。

        """

        #得到adjacent_vertexs_edges中顶点是'A'(nodes[0]='A')的相邻点list,即adjacent_vertexs['A']=[(7,'A','B'),(5,'A','D')]

        adjacent_vertexs_edges = adjacent_vertex[vertexs[0]]  

        #将usable_edges加入到堆中,并能够实现用heappop从其中动态取出最小值。关于heapq模块功能,参考python官方文档

        heapify(adjacent_vertexs_edges)

        while adjacent_vertexs_edges:
            #得到某个定点(做为adjacent_vertexs_edges的键)与相邻点距离(相邻点和边长/距离做为该键的值)最小值,并同时从堆中清除。
            w, v1, v2 = heappop(adjacent_vertexs_edges)
            if v2 not in chosed:

                #在used中有第一选定的点'A',上面得到了距离A点最近的点'D',举例是5。将'd'追加到used中
                chosed.add(v2)                          

                mst.append((v1,v2,w))          #将v1,v2,w,第一次循环就是('A','D',5) append into mst

                #再找与d相邻的点,如果没有在heap中,则应用heappush压入堆内,以加入排序行列

                for next_vertex in adjacent_vertex[v2]:
                    if next_vertex[2] not in chosed:
                        heappush( adjacent_vertexs_edges,next_vertex)
        return mst

    #test
    vertexs = list("ABCDEFG")
    edges = [ ("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)]

    print "edges:",edges
    print "prim:", prim( vertexs, edges )

运行结果

edges: [(‘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: [(‘A‘, ‘D‘, 5), (‘D‘, ‘F‘, 6), (‘A‘, ‘B‘, 7), (‘B‘, ‘E‘, 7), (‘E‘, ‘C‘, 5), (‘E‘, ‘G‘, 9)]

无向图最小生成树Prim算法

时间: 2024-10-11 07:30:30

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

最小生成树--prim算法

一个无向图G的最小生成树就是由该图的那些连接G的所有顶点的边构成的树,且其总价值最低,因此,最小生成树存在的充分必要条件为图G是连通的,简单点说如下: 1.树的定义:有n个顶点和n-1条边,没有回路的称为树 生成树的定义:生成树就是包含全部顶点,n-1(n为顶点数)条边都在图里就是生成树 最小:指的是这些边加起来的权重之和最小 2.判定条件:向生成树中任加一条边都一定构成回路 充分必要条件:最小生成树存在那么图一定是连通的,反过来,图是连通的则最小生成树一定存在 上图的红色的边加上顶点就是原图的

数据结构:最小生成树--Prim算法

最小生成树:Prim算法 最小生成树 给定一无向带权图,顶点数是n,要使图连通只需n-1条边,若这n-1条边的权值和最小,则称有这n个顶点和n-1条边构成了图的最小生成树(minimum-cost spanning tree). Prim算法 Prim算法是解决最小生成树的常用算法.它采取贪心策略,从指定的顶点开始寻找最小权值的邻接点.图G=<V,E>,初始时S={V0},把与V0相邻接,且边的权值最小的顶点加入到S.不断地把S中的顶点与V-S中顶点的最小权值边加入,直到所有顶点都已加入到S中

Highways POJ-1751 最小生成树 Prim算法

Highways POJ-1751 最小生成树 Prim算法 题意 有一个N个城市M条路的无向图,给你N个城市的坐标,然后现在该无向图已经有M条边了,问你还需要添加总长为多少的边能使得该无向图连通.输出需要添加边的两端点编号即可. 解题思路 这个可以使用最短路里面的Prim算法来实现,对于已经连接的城市,处理方式是令这两个城市之间的距离等于0即可. prim算法可以实现我们具体的路径输出,Kruskal算法暂时还不大会. 代码实现 #include<cstdio> #include<cs

hdu 3371 最小生成树prim算法

Connect the Cities Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8992    Accepted Submission(s): 2519 Problem Description In 2100, since the sea level rise, most of the cities disappear. Thoug

POJ1258最小生成树(prim算法)

POJ1258 思路:首先把第一个结点加入树中,每次往树中加入一个结点,加入的结点必须是与当前树中的结点距离最小那个点,这样每次把结点加入树中选取的都是最小权值,循环n-1次后把所有结点都加入树中. #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXN = 1e9; //创建map二维数组储存图表,low数组记录每2个点间最小权值,vis数组标记

poj1789Truck History(最小生成树prim算法)

题目链接: 啊哈哈,点我点我 思路:根据字符串中不同的长度建图,然后求图的最小生成树.. 题目: Truck History Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 18272   Accepted: 7070 Description Advanced Cargo Movement, Ltd. uses trucks of different types. Some trucks are used for vege

最小生成树のprim算法

Problem A Time Limit : 1000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 31   Accepted Submission(s) : 10 Problem Description 省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出了有可能建设公

无向图最小生成树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的实现方法.这两种方法均参考

E - Agri-Net (最小生成树) -- prim算法

http://acm.sdut.edu.cn:8080/vjudge/contest/view.action?cid=193#problem/E prim算法 思想和步骤总结 (自己所写) dis[],map[][],vis[],pos ,min,ans(主要定义的变量) 首先,prim算法用于计算图边径长度已知的图,它所求的是将图中所有顶点相连接,所需要的最短路径的长度,prim算法适合计算稠密图,它的主要思想是贪心思想,贪心准则为每次选择未加入树中且距离树最小的顶点,并用dis[]数组不断更