12.1 Prim算法
文章目录
- 最小生成树问题
- 几个概念
- 一般算法与Prim算法
- Python代码
- 案例的测试类代码
最小生成树问题
最小生成树问题是针对无向图的,事实上在计算机里存储的无向图,都是双向图。只有连通图才有生成树,图的生成树,就是包含了图的所有节点和部分边,但是没有环的子图。因为这个子图是一棵树,所以叫生成树。
最小生成树指的是权重和最小的生成树。
如以下就是一个无向图:
下面是它的一棵生成树:
但是这棵树毫无疑问不是最小生成树,因为它删除的是环中权重最小的边,最小生成树应该是删除环中最长的边,以下才是最小生成树:
几个概念
交叉cross,在我的博文最大流最小割定理里讲到了割的概念,交叉就是边的两端分布在割的两部分,也就是说这个边是割的边界处的连接边。
尊重respect,一个割尊重一个边的集合指的是这个集合里的所有边,都不与割交叉。
轻边light edge,割的交叉边里权重最小的边。
安全边sage edge,这个概念比较复杂。对于一个边的集合A,任意尊重A的割中的轻边就是安全边。
一般算法与Prim算法
一般算法,就是先从空集合开始构建边集A,然后不断寻找A的安全边,再把安全边加入到A中,直到把图的所有点都包含进去,此时A就是最小生成树。
Prim算法,就是选择割的时候做了唯一限定。因为一般算法里,割是任意选择的。Prim算法是以边集内包含的点为界限来选择割的。这样就唯一了。我以实际案例举个例子,以下是无向加权图图:
以点A为起始点:
安全边肯定是指向B喽:
这时候安全边有两个,A-C和B-D,按顺序选C吧:
下一个安全边明显是CF:
下一个安全边是CD和FG,按顺序选CD:
再选FG:
最后是FE:
Python代码
# _*_ coding:utf-8
class Edge:def __init__(self, to, weight):self.__to = toself.__weight = weight@propertydef to(self):return self.__to@to.setterdef to(self, to):self.__to = to@propertydef weight(self):return self.__weight@weight.setterdef weight(self, weight):self.__weight = weightWHITE = 0
GRAY = 1
BLACK = 2class WeightedGraph:def __init__(self, vertices, edges):self.__vertices = verticesself.__edges = edges@propertydef vertices(self):return self.__vertices@vertices.setterdef vertices(self, value):self.__vertices = value@propertydef edges(self):return self.__edges@edges.setterdef edges(self, value):self.__edges = valuedef prim_mst(self):# 初始化为空a = [[] for _ in self.vertices]s = [False for _ in self.__vertices]s[0] = Trues_len = 1n = len(self.__vertices)pos = ["0,0!", "2,1!", "2,-1!", "4,0!", "6,1!", "6,-1!", "8,0!", ]print(f"第{s_len}步", self.to_prim_dot(pos, s, a))while s_len < n:v, edge = self.safe_edge(s)a[v].append(edge)# 反向也要添加一下,因为是双向图a[edge.to].append(Edge(v, edge.weight))s[edge.to] = Trues_len += 1print(f"第{s_len}步", self.to_prim_dot(pos, s, a))return adef safe_edge(self, s):# 寻找安全边# 所有的边min_weight = Nonesage_edge = Nonestart = Nonefor v, exists in enumerate(s):if not exists:continueneighbors = self.__edges[v]for neighbor in neighbors:if s[neighbor.to]:continue# 此时是crossif min_weight is None or neighbor.weight < min_weight:min_weight = neighbor.weightsage_edge = neighborstart = vreturn start,sage_edgedef to_dot(self, pos):dot_s = 'graph s {\n\tlayout=fdp\n'for i, v in enumerate(self.__vertices):dot_s += f'\t"{v}"[pos="{pos[i]}"];\n'for i, e in enumerate(self.__edges):for t in e:if t.to < i:continuedot_s += f'\t\"{self.__vertices[i]}\"--"{self.__vertices[t.to]}"[label="{t.weight}"];\n'dot_s += '}\n'return dot_sdef to_prim_dot(self, pos, s, a):dot_s = 'graph s {\n\tlayout=fdp\n'for i, v in enumerate(self.__vertices):dot_s += f'\t"{v}"[pos="{pos[i]}";'if s[i]:dot_s += 'style=filled;fillcolor=red;'dot_s += '];\n'for i, e in enumerate(self.__edges):for t in e:if t.to < i:continuedot_s += f'\t\"{self.__vertices[i]}\"--"{self.__vertices[t.to]}"[label="{t.weight}";'for st_edge in a[i]:if st_edge.to == t.to:dot_s += 'color=red;'dot_s += '];\n'dot_s += '}\n'return dot_s
案例的测试类代码
import unittestfrom com.youngthing.graph.prim_mst import Edge
from com.youngthing.graph.prim_mst import WeightedGraphclass PrimMstTestCase(unittest.TestCase):def test_prim(self):# 做一张图vertices = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G',]# 设计容量edges = [[Edge(1, 4), Edge(2, 8), ],#a[Edge(0, 4), Edge(2, 9), Edge(3, 8), Edge(4, 10)],#B[Edge(0, 8), Edge(1, 9), Edge(3, 2), Edge(5, 1)],#C[Edge(1, 8), Edge(2, 2), Edge(4, 7), Edge(5, 9)],#D[Edge(1, 10), Edge(3, 7), Edge(5, 5), Edge(6, 6)],#E[Edge(2, 1), Edge(3, 9), Edge(4, 5), Edge(6, 2)],#f[Edge(4, 6), Edge(5, 2)],#g]fn = WeightedGraph(vertices, edges)pos = ["0,0!", "2,1!", "2,-1!", "4,0!", "6,1!", "6,-1!", "8,0!", ]print(fn.to_dot(pos))tree = fn.prim_mst()print(WeightedGraph(vertices, tree).to_dot(pos))if __name__ == '__main__':unittest.main()
12.1 Prim算法相关推荐
- C语言实现Prim算法与Kruskal算法(浙大 陈越版)
案例6-1.7 公路村村通 (30分) 现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本. 输入格式: 输入数据包括城镇数目正整数N ...
- 数据结构与算法(7-3)最小生成树(普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法)
目录 一.最小生成树简介 二.普里姆算法(Prim) 1.原理 2.存储 2-1.图顶点和权: 2-3. 最小生成树: 3.Prim()函数 3-1.新顶点入树 3-2.保留最小权 3-3. 找到最小 ...
- hdu 1233 还是畅通工程(最小生成树的Prim和Kruskal两种算法的c++实现)(prim算法详解)...
赤裸裸滴最小生成树(MST),刚学的玩意,用两种方法熟练一下.(都是greedy) Kruskal方法:先对边按照代价非递减排序,再不断添加边且不产生环路,当边数=点数-1结束.判断加入(v,w)是否 ...
- 浅谈最小生成树的算法思路(一)Prim算法
Prim算法是求最小生成树的一种常见算法,简单谈一下笔者自己的理解. 算法思路 设已经确定的点集为P,初始为空.设还未确定的点集为Q,初始为该图所有点的集合.设已经确定的边为X,初始为空. 选取任意一 ...
- 最小生成树之prim算法
一 背景 二 prim算法java版 package leaning.graph;/** 最小生成树之普里姆算法* */ public class PrimMiniCostSpanningTree ...
- prim算法 求最小生成树
最小生成树Prim算法理解 标签: Prim算法理解最小生成树Prim 2014-08-16 18:49 18482人阅读 评论(5) 收藏 举报 版权声明:本文为博主原创文章,未经博主允许不得转载. ...
- 为什么Prim算法不适用于带权有向图
其实,能不能使用Prim算法计算图的最小生成树,和这个图是有向图还是无向图,这两者之间没有必然的联系. 而是,如果在有向图中出现了以下情况,那么就不能使用Prim算法: 假设一个有向图有3个顶点 1- ...
- [OI学习笔记]最小生成树之Prim算法
背景 今天遇到这样一道题:(洛谷2820) 某个局域网内有n(n<=100)台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么 ...
- prim算法_数据结构 7.4.1 最小生成树 Prim
最小生成树 Minimum Spanning Tree 「最小生成树」这个词包含三部分信息 树 生成树 最小 什么是树? 树可以看做是一种特殊的图,「树没有回路」 有n个顶点的树一定有n-1条边 什么 ...
最新文章
- 阿里文娱搜索算法实践与思考
- C++ Openssl AES GCM 128bits代码示例,可wins10的visual studio 2017 中直接运行
- c++ using 前置声明_C++ 类声明 类前置声明范例
- 微信小程序_(表单组件)button组件的使用
- 【转】logback 常用配置详解(序)logback 简介
- java 最好 入门_C++和Java哪个比较好入门?初学者该如何选择?
- xcode 4.2下怎么添加framework?
- 关于STM32定时器使用的一个注意事项(以此为前车之鉴,重要!)
- 客户信息管理系统----Java实现(以对象数组为主)
- 调整IT外包业务合同 降低外包价格
- ieda-自动引入局部变量(introduce local variable)快捷键
- YOLOv5中autoanchor.py的def metric(k)的r = wh[:, None] / k[None]的理解
- 断言Assertion
- oracle 移动分区表到指定表空间,及修改表的默认表空间
- SC4020/SCv2020 控制器更换流程步骤和可能遇到的问题
- qq修改实名认证已达上限_和平精英解除防沉迷怎么弄 和平精英实名认证修改教程...
- 基于java+springboot+mybatis+vue+elementui的旧物置换网站
- DEEP COMPRESSION(深度学习网络参数压缩)
- 自己动手写工具:百度图片批量下载器
- 让这些浏览器插件和工具来帮你破解突破百度网盘下载速度太慢的难题!