Prim和Kruskal的区别?哪个好?

news2024/11/26 18:28:47

Prim和Kruskal有啥区别?到底哪个好?

今天做了一道最小生成树的题,发现了一点猫腻!
题目在这里 : 《修路问题1》


文章目录

  • Prim和Kruskal有啥区别?到底哪个好?
  • 先说结论
  • Prim
  • Kruskal
  • 修路问题1——题目描述
  • 总结


先说结论

Prim算法Kruskal算法 都是从连通图中找出 最小生成树 的经典算法~

从策略上来说,Prim算法是直接查找,多次寻找邻边的权重最小值,而 Kruskal是需要先对权重排序后查找的

所以说,Kruskal在算法效率上是比Prim快的 ,因为Kruskal只需一次对权重的排序就能找到最小生成树,而Prim算法需要多次对邻边排序才能找到~

Prim

Prim算法是一种产生最小生成树的算法。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;
并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。

Prim算法从任意一个顶点开始每次选择一个与当前顶点集最近的一个顶点,并将两顶点之间的边加入到树中。Prim算法在找当前最近顶点时使用到了贪婪算法。朴素版时间复杂度为:O(n²) ,堆优化过后的prim时间复杂度为O(mlogn)

算法描述:

  1. 在一个加权连通图中,顶点集合V,边集合为E
  2. 任意选出一个点作为初始顶点,标记为visit,计算所有与之相连接的点的距离,选择距离最短的,标记visit.
  3. 重复以下操作,直到所有点都被标记为visit:
    在剩下的点中,计算与已标记visit点距离最小的点,标记visit,证明加入了最小生成树。

在这里插入图片描述

Kruskal

Kruskal是另一个计算最小生成树的算法,其算法原理如下。首先,将每个顶点放入其自身的数据集合中。然后,按照权值的升序来选择边。当选择每条边时,判断定义边的顶点是否在不同的数据集中。如果是,将此边插入最小生成树的集合中,同时,将集合中包含每个顶点的联合体取出,如果不是,就移动到下一条边。重复这个过程直到所有的边都探查过。

在这里插入图片描述
在这里插入图片描述

第1步:将边<E,F>加入R中。
边<E,F>的权值最小,因此将它加入到最小生成树结果R中。
第2步:将边<C,D>加入R中。
上一步操作之后,边<C,D>的权值最小,因此将它加入到最小生成树结果R中。
第3步:将边<D,E>加入R中。
上一步操作之后,边<D,E>的权值最小,因此将它加入到最小生成树结果R中。
第4步:将边<B,F>加入R中。
上一步操作之后,边<C,E>的权值最小,但<C,E>会和已有的边构成回路;因此,跳过边<C,E>。同理,跳过边<C,F>。将边<B,F>加入到最小生成树结果R中。
第5步:将边<E,G>加入R中。
上一步操作之后,边<E,G>的权值最小,因此将它加入到最小生成树结果R中。
第6步:将边<A,B>加入R中。
上一步操作之后,边<F,G>的权值最小,但<F,G>会和已有的边构成回路;因此,跳过边<F,G>。同理,跳过边<B,C>。将边<A,B>加入到最小生成树结果R中。

修路问题1——题目描述

在这里插入图片描述
在这里插入图片描述
输入示例:

5 6
1 2 2
1 3 7
1 4 6
2 3 1
3 4 3
3 5 2

输出

8

Kruskal(过了100%)

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;

/**
 * Created with IntelliJ IDEA.
 *
 * @Auther: LiangXinRui
 * @Date: 2023/3/3 9:07
 * @Description: Kruskal算法在找最小生成树结点之前,需要对权重从小到大进行排序。
 * 将排序好的权重边依次加入到最小生成树中(如果加入时产生回路就跳过这条边,加入下一条边),
 * 当所有的结点都加入到最小生成树中后,就找到了这个连通图的最小生成树~
 */
public class demo83_kruskal_修建公路 {
    static final int N = 300005;
    static int n,m,count;
    static long sum;
    static Edge[] edges = new Edge[N];
    static int[] pre = new int[N];
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    static int find(int v) {
        if (v != pre[v]) {
            pre[v] = find(pre[v]);
        }
        return pre[v];
    }

    public static void main(String[] args) throws Exception {
        String[] s = br.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        m = Integer.parseInt(s[1]);
        for (int i = 1; i <= n; i++) {
            pre[i] = i;
        }
        for (int i = 0; i < m; i++) {
            String[] s1 = br.readLine().split(" ");
            int a, b, c;
            a = Integer.parseInt(s1[0]);
            b = Integer.parseInt(s1[1]);
            c = Integer.parseInt(s1[2]);
            edges[i] = new Edge(a, b, c);
        }
        Arrays.sort(edges, 0, m);

        for (int i = 0; i < m; i++) {
            int a = edges[i].a;
            int b = edges[i].b;
            int w = edges[i].w;
            a = find(a);
            b = find(b);
            if (a != b) {//这里不能写成 if (find(a) != find(b))
                pre[a] = b;
                sum += w;
                count++;
            }
        }
        if (count == n - 1) {
            System.out.println(sum);
        } else {
            System.out.println(-1);
        }

    }

    static class Edge implements Comparable<Edge> {
        int a;
        int b;
        int w;

        Edge(int a, int b, int w) {
            this.a = a;
            this.b = b;
            this.w = w;
        }

        public int compareTo(Edge e) {
            return w - e.w;
        }
    }
}



堆优化的prim(过了60%,有可能哪儿写错了?)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

/**
 * @Author: LiangXinRui
 * @Date: 2023/03/02/20:16
 * @Description:
 */

public class demo83_prim_堆优化 {
    static int[] head, next, ends, pre;
    static int n, m, num, total, begin;
    static double sum;
    static double[] weights, dis;
    static boolean[] vis;
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    static class pair {
        double first;//记录 边权
        int second;//记录 下一个结点

        public pair() {
        }

        public pair(double first, int second) {
            this.first = first;
            this.second = second;
        }
    }

    //自定义比较类,升序排列
    static Comparator<pair> comparator = (o1, o2) -> o1.first - o2.first > 0 ? 1 : 0;
    
    static Queue<pair> queue = new PriorityQueue<>(comparator);

    static void add(int start, int end, int weight) {
        ends[total] = end;
        weights[total] = weight;
        next[total] = head[start];
        head[start] = total;
        total++;
    }

    static void prim() {
        queue.offer(new pair(weights[0], ends[0]));
        vis[begin] = true;
        while (!queue.isEmpty() && num < n) {
            double len = queue.peek().first;
            int to = queue.peek().second;
            queue.poll();
            if (!vis[to]) {
                sum += len;
                num++;// 找到一条边
                vis[to] = true;// 标记一下,表示我这条边已经用过
                for (int i = head[to]; i != -1; i = next[i]) {
                    if (weights[i] < dis[ends[i]]) {// 如果当前边权小,更新
                        dis[ends[i]] = weights[i];
                        queue.offer(new pair(weights[i], ends[i]));// 把新的边权和结点加入队列
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        String[] firstStr = br.readLine().split(" ");
        n = Integer.parseInt(firstStr[0]);
        m = Integer.parseInt(firstStr[1]);
        dis = new double[n + 1];
        head = new int[2 * m + 1];//表示以 i 为起点的最后一条边的编号
        next = new int[2 * m + 1];//存储与当前边起点相同的上一条边的编号
        ends = new int[2 * m + 1];//存储边的终点
        weights = new double[2 * m + 1];//存储边的权值
        vis = new boolean[2 * m + 1];
        Arrays.fill(head, -1);//初始化
        for (int i = 1; i <= n; i++) {
            dis[i] = Double.MAX_VALUE / 2;
        }
        for (int i = 0; i < m; i++) {
            String[] secondStr = br.readLine().split(" ");
            int start = Integer.parseInt(secondStr[0]);
            if (i == 0) begin = start;
            int end = Integer.parseInt(secondStr[1]);
            int weight = Integer.parseInt(secondStr[2]);
            add(start, end, weight);
            add(end, start, weight);
        }
        prim();
        if (n - 1 == num) {
            System.out.printf("%.0f", sum);
        } else {
            System.out.println("-1");
        }
    }

}


总结

遇到困难时首先想到的不应该是退缩,而是探索!

文章粗浅,希望对大家有帮助!

参考博客:
【最小生成树】Prim算法和Kruskal算法的区别对比
Prim算法(java)
克鲁斯卡尔算法(Kruskal)详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/384749.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EPICS Phoebus手册1

1、介绍 Phoebus是一个控制系统Stdio工具集的更新&#xff0c;它移除了对Eclipse RCP和SWT的依赖。 虽然Eclipse RCP快速启动了原先的CS-Studio的实现&#xff0c;并且为CS-Stdio也提供了大约十年的服务&#xff0c;因为RCP也增加了对控制系统用户接口开发的限制。 Phoebus项目…

【Spring源码】AOP的开端:核心对象创建的准备工作

AOP的核心成员是如何被被加载的&#xff1f;本篇我们主要分析使用xml的逻辑&#xff0c;如果使用注解&#xff0c;增加注解处理类即可&#xff08;ConfigurationClassPostProcessor&#xff09;拿之前分析循环的时候举的例子&#x1f330;&#xff0c;它的日志切面就是通过xml进…

119.(leaflet篇)文字碰撞

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

如何从 Android 手机上的 SD 卡恢复已删除的照片

为了扩展手机的存储空间&#xff0c;很多人都会在安卓手机上插入一张SD卡来存储一些大文件&#xff0c;比如电影、照片、视频等。虽然SD卡给我们带来了很大的方便&#xff0c;但我们还是避免不了数据丢失一些事故造成的。您是否正在为 SD 卡上的照片意外丢失而苦恼&#xff1f;…

工作中常用且容易遗忘的css样式整理,建议收藏

1. 文字超出部分显示省略号单行文本的溢出显示省略号&#xff08;一定要有宽度&#xff09;p{width:200rpx;overflow: hidden;text-overflow:ellipsis;white-space: nowrap;}多行文本溢出显示省略号p {display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: …

干货干货FPGA lattice深力科 FPGA性能优势以及市场前景分析 以及lattice MachXO2系列MachXO3系列资料参考

干货干货FPGA lattice深力科 FPGA性能优势以及市场前景分析 以及lattice MachXO2系列MachXO3系列资料参考 那什么是FPGA芯片呢&#xff1f;FPGA全称为&#xff1a;现场可编程逻辑门阵列&#xff08;Field-Programmable Gate Array&#xff09;&#xff0c;是基于通用逻辑电路阵…

C语言实现顺序表(pushback pushfront popback popfront insert erase find)

顺序表&#xff0c;是常用的一种数据结构&#xff0c;他的底层是连续的物理内存&#xff0c;所以他可以在O&#xff08;1&#xff09;的时间访问下标为N的位置&#xff0c;而且很多操作都是基于顺序表才可以操作的&#xff0c;例如:排序 所以顺序表是很重要的&#xff0c;他和…

taobao.item.update.listing( 一口价商品上架 )

&#xffe5;开放平台基础API必须用户授权 单个商品上架输入的num_iid必须属于当前会话用户 公共参数 请求地址: HTTP地址 http://gw.api.taobao.com/router/rest 公共请求参数: 请求参数 响应参数 点击获取key和secret 请求示例 TaobaoClient client new DefaultTaobaoCl…

SpringBoot入门 - 定制自己的Banner

我们在启动Spring Boot程序时&#xff0c;有SpringBoot的Banner信息&#xff0c;那么如何自定义成自己项目的信息呢&#xff1f;什么是Banner我们在启动Spring Boot程序时&#xff0c;有如下Banner信息&#xff1a;那么如何自定义成自己项目的名称呢&#xff1f;如何更改Banner…

一天约了4个面试,复盘一下面试题和薪资福利

除了最新的面经分享&#xff0c;还有字节大佬的求职面试答疑&#xff0c;告诉你关键问题是什么&#xff1f;少走弯路。**另外本文也汇总了6份大厂面试题&#xff1a;字节、腾讯、小米、腾讯云、滴滴、小米游戏。**希望对大家有帮助。 前言 昨天我的交流群里&#xff0c;有位宝…

【学习笔记】深入理解JVM之对象的实例化

参考尚硅谷JVM 102 - 106 集 首发地址&#xff1a;地址 1、JVM对象的实例化 1.1 对象的创建方式 对象有一下几种创建对象的方式 new Object object new Object();Class的newInstance() Object object Object.class.newInstance();Constructor的newInstance&#xff08…

精选博客系列|公用事业中的VMware:在边缘重新定义价值

VMware 已经成为公用事业行业的核心。您可以在那里找到例如 VMware vSphere&#xff08;包括基础 Hypervisor ESXi 和 VMware vCenter 建立的整体控制平面&#xff09;的核心产品。来自软件定义的基础架构带来的诸多好处使 IT 团队将其先前基于硬件的系统转变为 VMware Cloud F…

GPT+时代来临:OpenAI开放GPT3.5模型,1000token仅1毛钱

GPT3.5 Model API 使用指南 今天OpenAI公司开放了最新的GPT3.5模型&#xff1a;gpt-3.5-turbo&#xff0c;也就是目前网页版的ChatGPT使用的模型。而此前OpenAI开放的最新的模型text-davinci-003则是基于GPT3模型构建的。并且价格十分便宜&#xff1a;1000 token/0.002美元&am…

CVE-2021-2109 WebLogic JNDI 注入

0x01 前言学习一下 WebLogic JNDI 注入 RCE&#xff08;CVE-2021-2109&#xff09;0x02 环境搭建和之前 WebLogic 的环境搭建是一致的&#xff0c;本文不再赘述。不过值得一提的是&#xff0c;我的 weblogic 版本是 10.3.6&#xff1b;需要手动添加 \server\lib\consoleapp\web…

打电话,玩手机、摔倒行人行为识别

文章大纲 数据集准备一些难点paddle 解决方案行为识别打电话摔倒开源解决方案前文: 深度学习与视频分析简介视频分析:基于目标检测(YOLO)实现走路看手机检测、玩手机检测、跌倒检测等数据集准备 我们可以从开源数据中挑选一些 参考文章: 使用python 脚本挑出coco 数据集…

【C++的OpenCV】第九课-OpenCV图像常用操作(六):图像形态学-阈值的概念、功能及操作(threshold()函数))

目录一、阈值&#xff08;thresh&#xff09;的概念二、阈值在图形学中的用途三、阈值的作用和操作3.1 在OpenCV中可以进行的阈值操作3.2 操作实例3.2.1 threshold()函数介绍3.2.2 实例3.2.3 结果上节课的内容&#xff08;作者还是鼓励各位同学按照顺序进行学习哦&#xff09;&…

易基因|m6A RNA甲基化研究的数据挖掘思路:干货系列

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。关于m6A甲基化研究思路&#xff08;1&#xff09;整体把握m6A甲基化图谱特征&#xff1a;m6A peak数量变化、m6A修饰基因数量变化、单个基因m6A peak数量分析、m6A peak在基因元件上的分布…

IP协议的漏洞及防护措施

文章目录一、TCP/IP协议族二、IP协议三、IP协议的安全问题及防护措施一、TCP/IP协议族 二、IP协议 网际协议&#xff08;Internet Protocol&#xff0c;IP&#xff09;是TCP/IP协议族的核心&#xff0c;也是网际层最重要的协议。 IP数据报由首部和数据两部分组成&#xff1b…

Spark性能优化五 算子优化

文章目录&#xff08;一&#xff09;map 和 mapPartitions&#xff08;二&#xff09;foreach 和 foreachPartition&#xff08;三&#xff09;repartition的使用&#xff08;四&#xff09;reduceByKey 和 groupByKey的区别&#xff08;一&#xff09;map 和 mapPartitions m…

解决Visual C++ Redistributable安装找不到vc_runtimeMinimum_x86.msi最简单办法

今天在安装Fritzing的时候&#xff0c;遇到了需要Visual C Redistributable支持包&#xff0c;所以就动手安装&#xff0c;发现居然不能安装&#xff0c;安装几次居然错误提示所需要的安装包*.MSI的居然名称还不用。我也是下载了各种版本来试图靠运气过关&#xff0c;结果失败告…