Prim算法和Kruskal算法到底哪个好?

news2025/1/31 3:07:29

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/396583.html

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

相关文章

不好!有敌情,遭到XSS攻击【网络安全篇】

XSS&#xff1a;当一个目标的站点&#xff0c;被我们用户去访问&#xff0c;在渲染HTMl的过程中&#xff0c;出现了没有预期到的脚本指令&#xff0c;然后就会执行攻击者用各种方法注入并执行的恶意脚本&#xff0c;这个时候就会产生XSS。 涉及方&#xff1a; 用户&#xff0…

Linux端安装MySQL并实现远程连接Navicat

文章目录Linux端安装MySQL&#xff08;centos版本&#xff09;Linux端安装MySQL&#xff08;centos版本&#xff09; 1、先将MySQL需要的四个rpm安装包上传上去&#xff0c;这里可以使用Xftp软件或者是通过window端使用ftp文件传输方式上传到Linux端&#xff0c;这里选择Xftp来…

基于JavaWeb学生选课系统开发与设计(附源码资料)

文章目录1. 适用人群2. 你将收获3.项目简介4.技术实现5.运行部分截图5.1.管理员模块5.2.教师模块5.3.学生模块1. 适用人群 本课程主要是针对计算机专业相关正在做毕业设计或者是需要实战项目的Java开发学习者。 2. 你将收获 提供&#xff1a;项目源码、项目文档、数据库脚本…

远程办公18年,把一个开源工具变成了价值 75亿美元的跨国企业

把自己的兴趣做成了一份事业&#xff0c;把一个开源工具发展成为一家价值75亿美元的跨国企业&#xff0c;而且还是那种员工做梦都想进入的公司&#xff0c;真正实现了功成名就&#xff0c;这或许是所有程序员的梦想吧。 先来看看这家公司的福利&#xff1a; 员工拥有没有限制的…

git快速入门(1)

1 git的下载与安装1&#xff09;下载git安装包下载路径&#xff1a;https://git-scm.com/我的操作系统是window&#xff0c;64位的&#xff0c;我下载的Git-2.33.0-64-bit.exe&#xff0c;从官网下载或者从网址下载链接&#xff1a;链接地址&#xff1a;https://pan.baidu.com/…

【MySQL】P8 多表查询(2) - 连接查询 联合查询

连接查询以及联合查询多表查询概述连接查询内连接隐式内连接显式内连接外连接左外连接右外连接自连接联合查询多表查询概述 建表语句见上一篇博文&#xff1a;https://blog.csdn.net/weixin_43098506/article/details/129402302 e.g.e.g.e.g. select * from emp, dept where e…

深入分析@Configuration源码

文章目录一、源码时序图1. 注册ConfigurationClassPostProcessor流程源码时序图2. 注册ConfigurationAnnotationConfig流程源码时序图3. 实例化流程源码时序图二、源码解析1. 注册ConfigurationClassPostProcessor流程源码解析&#xff08;1&#xff09;运行案例程序启动类Conf…

Python安装、断点调试

一、安装Python方法 1.1 在Microsoft Store微软商店中搜索Python安装&#xff08;推荐&#xff09; 或直接在cmd中Python运行 已经安装了就显示版本号&#xff0c; 如果没有安装过&#xff0c;会直接跳到微软商店 1.2 在python官网中找最新版下载安装 二、VSCODE中运行与断点…

容易混淆的嵌入式(Embedded)术语

因为做嵌入式开发工作虽然跳不出电子行业&#xff0c;但还是能接触到跨度较大的不同行当&#xff0c;身处不同的圈子。诸如医疗&#xff0c;银行&#xff0c;车载&#xff0c;工业&#xff1b;亦或者手机&#xff0c;PC&#xff0c;专用芯片&#xff1b;甚至可能横跨系统开发、…

Vue常见的事件修饰符

前言 vue一共给我们准备了6个事件修饰符&#xff0c;前三个比较常用&#xff0c;后三个少见&#xff0c;这里着重讲下前三个 1.prevent:阻止默认事件(常用) 2. stop:阻止事件冒泡(常用) 3. once:事件只触发一次(常用) 4.captrue:使用事件的捕捉模式(不常用) 5.self:只有event…

案例10---对生产环境的敬畏--生产环境

一&#xff1a;背景介绍 1&#xff1a;上午9:23&#xff0c;老师没有进行上课&#xff0c;但是却又很多的在线人员&#xff0c;并且在线人员的时间也不正确&#xff0c;用户反映问题。 2&#xff1a;开发人员发现用户上课情况异常。 3&#xff1a;10点整&#xff0c;询问项目…

Notepad++ 下载与安装教程

文章目录Notepad 下载与安装教程Notepad 简介一&#xff0c;Notepad 下载二&#xff0c;Notepad 安装Notepad 下载与安装教程 Notepad 简介 Notepad是程序员必备的文本编辑器&#xff0c;Notepad中文版小巧高效&#xff0c;支持27种编程语言&#xff0c;通吃C,C ,Java ,C#, XM…

Android Execution failed for task ‘:app:mergeDebugJavaResource

错误提示 FAILURE: Build failed with an exception.* What went wrong: Execution failed for task :app:mergeDebugJavaResource. > A failure occurred while executing com.android.build.gradle.internal.tasks.MergeJavaResWorkAction> 2 files found with path k…

不写代码、年薪百万,带你玩赚ChatGPT提示工程-提示应用程序

文章目录前言一、数据生成二、PAL (Program-Aided Language Models): Code as Reasoning总结前言 随着ChatGPT的大火&#xff0c;提示工程在大模型中的重要性不言而喻&#xff0c;本文参考国外Prompt Engineering Guide完成国内中文版本的《提示工程指南》&#xff0c;希望能够…

一文读懂倒排序索引涉及的核心概念

基础概念相信对于第一次接触Elasticsearch的同学来说&#xff0c;最难理解的概念就是倒排序索引&#xff08;也叫反向索引&#xff09;&#xff0c;因为这个概念跟我们之前在传统关系型数据库中的索引概念是完全不同的&#xff01;在这里我就重点给大家介绍一下倒排序索引&…

DOTA双功能螯合剂127985-74-4,p-SCN-Bn-DOTA,实验室科研试剂

p-SCN-Bn-DOTA产品描述&#xff1a;p-SCN-Bn-DOTA用于标记多肽的双功能螯合剂&#xff0c;同时螯合放射性核素和连接单克隆抗体。DOTA 的全名是 1,4,7,10-Tetraazacyclododecane-1,4,7,10-tetraacetic acid&#xff0c;中文名称为 1,4,7,10-四氮杂环十二烷-四乙酸&#xff0c;其…

Linux中断操作

一、thread_irq在内核中&#xff0c; 除了可以通过request_irq() 、 devm_request_irq()申请中断以外&#xff0c; 还可以通过以下二个函数申请( 它们比request_irq和devm_request_irq多了一个参数thread_fn)。 用这两个API申请中断的时候&#xff0c; 内核会为相应的中断号分配…

steam海外道具搬运,2个月变现1.6万,真的假的?

这几年的环境&#xff0c;让我这个身负房贷的房奴&#xff0c;实在是喘不过来气&#xff01; 也是无意间在朋友圈看到&#xff0c;之前突然裸辞的同事&#xff0c;不知道干什么发了财&#xff0c;竟然自己开了公司&#xff01; 几经询问才知道&#xff0c;他就是利用steam海外…

微内核架构的理解

什么是微内核架构 相信大家都听说过微内核架构&#xff0c;也或多或少做过一些类似于微内核架构的设计&#xff0c;为了可以更好的设计出微内核的架构&#xff0c;我们了解下什么是微内核架构。 说到微内核架构&#xff0c;大家首先会想到的是Eclips、IDEA、OSGI、Spring Plugi…

CAD连续标注怎么操作?CAD连续标注尺寸命令使用技巧

CAD标注工具可以在图形中创建多种标注&#xff0c;并可对标注样式进行修改或编辑。但是有些新手设计师在绘图过程中&#xff0c;不知道CAD连续标注怎么操作&#xff0c;其实很简单&#xff0c;本节内容就给大家分享一下浩辰CAD软件中CAD连续标注尺寸命令的使用技巧吧&#xff0…