2022.3.29 图论——PRIM 最小生成树算法


一、Prim 算法

参考文章

1.Prim 算法的核心原理:切分定理

切分:将一幅图分为两个不重叠且非空的节点集合
在这里插入图片描述
切分定理:
对于任意一种「切分」,其中权重最小的那条「横切边」一定是构成最小生成树的一条边。

使用切分定理,既然每一次「切分」一定可以找到最小生成树中的一条边,那我们就可以对图随意进行切分,每次都把权重最小的「横切边」拿出来加入最小生成树,直到把构成最小生成树的所有边都切出来为止。

2.切分流程

按照「切分」的定义,只要把图中的节点切成两个不重叠且非空的节点集合即可算作一个合法的「切分」,那么只切出来一个节点,也算是一个合法的「切分」

假设就从 A 点开始切分:
将节点A的所有横切边表示为 cut({A})
在这里插入图片描述
既然这是一个合法的「切分」,那么按照切分定理,这些「横切边」AB, AF 中权重最小的边一定是最小生成树中的一条边:
在这里插入图片描述
现在已经找到最小生成树的第一条边(边 AB),接下来围绕 A 和 B 这两个节点做切分:
在这里插入图片描述
然后又可以从这个切分产生的横切边(图中蓝色的边)中找出权重最小的一条边,也就又找到了最小生成树中的第二条边 BC:
在这里插入图片描述
接下来再围绕着 A, B, C 这三个点做切分,产生的横切边中权重最小的边是 BD,那么 BD 就是最小生成树的第三条边:
在这里插入图片描述
直到找到最小生成树的所有边为止。

3.Prim算法实现

切分具有以下性质:
在这里插入图片描述
即节点 A, B, C 的所有「横切边」(cut({A, B, C}))为节点A, B 的所有横切边与节点C的横切边(节点C的所有相邻边)之和。也就是说,在进行切分的过程中,我们只要不断把新节点的邻边加入横切边集合,就可以得到新的切分的所有横切边,同时用一个布尔数组 inMST 辅助,防止重复计算横切边就行了

代码实现:

class Prim {
   
    // 核心数据结构,存储「横切边」的优先级队列
    private PriorityQueue<int[]> pq;
    // 类似 visited 数组的作用,记录哪些节点已经成为最小生成树的一部分
    private boolean[] inMST;
    // 记录最小生成树的权重和
    private int weightSum = 0;
    // graph 是用邻接表表示的一幅图,
    // graph[s] 记录节点 s 所有相邻的边,
    // 三元组 int[]{from, to, weight} 表示一条边
    private List<int[]>[] graph;

    public Prim(List<int[]>[] graph) {
   
        this.graph = graph;
        this.pq = new PriorityQueue<>((a, b) -> {
   
            
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值