最小生成树,prim算法

news2024/9/20 21:54:58

Prim算法和Kruskal算法都是用于解决最小生成树问题的经典算法,它们在不同情况下有不同的适用性和特点。

Prim算法:

Prim算法是一种贪心算法,用于构建一个无向图的最小生成树。算法从一个初始节点开始,逐步添加与当前树连接且具有最小权重的边,直到所有节点都被连接。Prim算法的基本思想是从一个起始节点出发,每次选择一个与当前最小生成树相连的节点中,权重最小的边,将这个节点加入最小生成树中,并将其相连的边考虑进来。这样逐步扩展最小生成树,直至所有节点都被包含。

Kruskal算法:

Kruskal算法也是一种贪心算法,用于构建一个无向图的最小生成树。该算法首先将图中的所有边按照权重从小到大进行排序,然后从最小权重边开始,依次将边加入生成树中,但要保证加入边不会形成环。如果加入某条边会导致环的形成,则放弃该边,继续考虑下一条权重较小的边,直到生成树中包含了所有的节点。

区别:

基本思想:Prim算法从一个起始节点开始,逐步添加与当前最小生成树相连的具有最小权重的边。Kruskal算法通过排序边,然后逐个添加边,保证不形成环。

顶点处理:Prim算法在每一步选择中,仅考虑与当前已选择顶点相连的顶点,直接操作顶点Kruskal算法是通过遍历边的方式进行操作,不直接关心顶点。

数据结构:Prim算法通常使用优先队列(最小堆)来维护待选的边,以便每次选择具有最小权重的边。Kruskal算法则通常使用并查集来判断是否会形成环。

性能:在边的数量较少,而顶点的数量较多时,Prim算法通常会更有效。而在边的数量较多,而顶点的数量较少时,Kruskal算法可能更适用。

复杂度:Prim算法的时间复杂度通常在 O(V^2) 到 O(E* log(V)) 之间,取决于实现方式。Kruskal算法的时间复杂度主要由排序边的复杂度决定,通常为 O(E * log(E))。

总的来说,两种算法都能有效地构建最小生成树,但在不同情况下选择合适的算法可以提高效率。

1135. 最低成本联通所有城市

想象一下你是个城市基建规划者,地图上有 n 座城市,它们按以 1 到 n 的次序编号。

给你整数 n 和一个数组 conections,其中 connections[i] = [xi, yi, costi] 表示将城市 xi 和城市 yi 连接所要的costi(连接是双向的)。

返回连接所有城市的最低成本,每对城市之间至少有一条路径。如果无法连接所有 n 个城市,返回 -1

该 最小成本 应该是所用全部连接成本的总和。

在这里插入图片描述
代码实现:

// 定义边
struct Edge{
    int city;
    int cost;
};

// 定义 边的比较方法
// cost值较小的Edge对象具有更高的优先级,
// 因为EdgeComparator在a的cost大于b的cost时返回true,
// 这意味着在优先级队列中,a应该在b之后。
// 所以,这个优先级队列是一个最小堆(min heap),即队列顶部总是cost最小的Edge对象
struct EdgeComparator{
    bool operator()(const Edge& a,const Edge& b){
        return a.cost>b.cost;
    }
};

class Solution {
public:
    int minimumCost(int n, vector<vector<int>>& connections) {
        // 连接所有点需要的cost
        int cost = 0;
        vector<vector<Edge>> edges(n+1);
        // 定义访问数组
        vector<bool> visited(n+1,false);
        //  定义优先队列, cost小的排在前面
        priority_queue<Edge, vector<Edge>, EdgeComparator> minHeap;

        visited[1] = true;// 从城市1开始

        // 建立Edge二维数组
        // 每个点会对应一个list,每个list中存储:和这个点相连的城市以及到相连城市的距离
        for(const auto& conn:connections){
            // 是双向的
            edges[conn[0]].push_back(Edge{conn[1],conn[2]});
            edges[conn[1]].push_back(Edge{conn[0],conn[2]});
        }
        // 先把和1点相连的Edge进行排序,放入优先队列
        for(const Edge& edge:edges[1]){
            minHeap.push(edge);
        }
        // 连接点的数量,初始为1
        int count = 1;
        while(!minHeap.empty()){
            Edge e = minHeap.top();
            minHeap.pop();

            if(visited[e.city]){
                // 如果已经访问过某一点了,则直接进入下一次循环
                continue;
            }

            // 如果没有访问过,就设置为true
            visited[e.city] = true;

            // 再把和这个点相连的Edge push进优先队列
            for(const Edge& edge:edges[e.city]){
                minHeap.push(edge);
            }
            cost += e.cost;
            // 连接点的数量+1
            count++;

            if(count == n){
                return cost;
            }
        }
        return -1;
    }
};

1584. 连接所有点的最小费用

给你一个points 数组,表示 2D 平面上的一些点,其中 points[i] = [xi, yi] 。

连接点 [xi, yi] 和点 [xj, yj] 的费用为它们之间的 曼哈顿距离 :|xi - xj| + |yi - yj| ,其中 |val| 表示 val 的绝对值。

请你返回将所有点连接的最小总费用。只有任意两点之间 有且仅有 一条简单路径时,才认为所有点都已连接。

在这里插入图片描述

完全仿照上面一题的代码,写出了这题的代码,唯二的区别在于,需要自己额外计算一下每个点之间的距离,并且不满足条件时返回0:

// 定义结构体Edge
struct Edge{
    int city;
    int cost;
};

struct EdgeComparator{
    bool operator()(const Edge& a,const Edge& b){
        return a.cost>b.cost;
    }
};

// 计算曼哈顿距离
int compute_Manhattan(vector<vector<int>>& points,int p1,int p2){
    return abs(points[p1][0]-points[p2][0]) + abs(points[p1][1]-points[p2][1]);
}

class Solution {
public:
    int minCostConnectPoints(vector<vector<int>>& points) {
       int cost = 0;
       int n = points.size();// 点的个数
       vector<vector<Edge>> edges(n);
       priority_queue<Edge, vector<Edge>, EdgeComparator> minHeap;
       vector<bool> visited(n,false); // 访问数组

       visited[0] = true; // 从0点开始search

       int count = 1; // 已经访问到了的点(已经相连的点)

       // 建立了 邻接表
       for(int i = 0;i<n-1;i++){
           for(int j = i+1;j<n;j++){
               // 两点间的曼哈顿距离
               int distance = compute_Manhattan(points,i,j);
               edges[i].push_back(Edge{j,distance});
               edges[j].push_back(Edge{i,distance});
           }
       }

        // 把和0点相关的点push进最小堆
        for(const Edge& edge:edges[0]){
            minHeap.push(edge);
        }

        while(!minHeap.empty()){
            Edge e = minHeap.top();
            minHeap.pop();

            if(visited[e.city]){
                // 如果已经访问过该点,则进入下一次循环
                continue;
            }
            visited[e.city] = true; // 标记访问过该点

            // 再把和该点相连的点push 进 minHeap
            for(const Edge& edge:edges[e.city]){
                minHeap.push(edge);
            }

            cost += e.cost; // 加上和这个点相连的cost
            count++;

            if(count == n){
                // 如果n个点都相连了,返回cost即可
                return cost;
            }
        }
        return 0;
    }
};

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

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

相关文章

08 - 网络通信优化之IO模型:如何解决高并发下IO瓶颈?

提到 Java I/O&#xff0c;相信你一定不陌生。你可能使用 I/O 操作读写文件&#xff0c;也可能使用它实现 Socket 的信息传输…这些都是我们在系统中最常遇到的和 I/O 有关的操作。 我们都知道&#xff0c;I/O 的速度要比内存速度慢&#xff0c;尤其是在现在这个大数据时代背景…

SqlServer 快速数据库脚本迁移

文章目录 前言数据库脚本数据库->任务->生成脚本选择数据库对象高级 如何迁移&#xff1a;脚本修改 如何使用新建数据库 前言 做工业的&#xff0c;经常遇到内网的项目&#xff0c;就是数据往本地的数据库传。由于这个问题所以我们需要新建一个数据库。最合适的就是数据…

微服务—远程调用(RestTemplate)

在微服务的所有框架中&#xff0c;SpringCloud脱颖而出&#xff0c;它是目前国内使用的最广泛的微服务框架 &#xff08;官网地址&#xff09;&#xff0c;它集成了各种微服务功能组件&#xff0c;并基于SpringBoot实现了这些组件的自动装配&#xff0c;从而提供了良好的开箱…

Html+JavaScript实现手写签名

前言 Hello各位&#xff0c;本葡萄又来啦&#xff0c;今天遇到的场景是这样的&#xff1a;在日常业务流程中&#xff0c;经常需要某一流程环节中相关责任人员进行审批签字&#xff0c;早期许多公司为了省事就直接会把这位负责人的签名以键盘打字&#xff08;楷体&#xff09;的…

Vue CLI创建Vue项目详细步骤

&#x1f680; 一、安装Node环境&#xff08;建议使用LTS版本&#xff09; 在开始之前&#xff0c;请确保您已经安装了Node.js环境。您可以从Node.js官方网站下载LTS版本&#xff0c;以确保稳定性和兼容性。 中文官网下载 确认已安装 Node.js。可以在终端中运行 node -v 命令…

vite+vue3项目配置cdn引入在线依赖

采用ejs的方式 安装语法依赖 npm install vite-plugin-ejs -D配置暴露数据 vite.config.js文件&#xff1a; import { fileURLToPath, URL } from node:url import { defineConfig, loadEnv } from vite import vue from vitejs/plugin-vue import vueJsx from vitejs/plug…

常用的分布式计算引擎

记录一下&#xff0c;作为备忘。 常用的分布式计算引擎 多表关联的问题&#xff0c;由于NoSQL数据库主要用于海量存储和单表查询&#xff0c;一般都不支持join&#xff0c;需借助更上层的计算框架来实现多表关联&#xff0c;比如: 计算框架支持数据源执行效率Hive本地文件、…

长胜证券:宁德时代发布神行超充电池 信创利好政策陆续出台

昨日&#xff0c;两市股指早盘震动回升&#xff0c;午后再度回落&#xff0c;尾盘加快下行。截至收盘&#xff0c;沪指跌0.82%报3150.13点&#xff0c;深成指跌0.94%报10579.56点&#xff0c;创业板指跌0.73%报2132.97点&#xff0c;科创50指数跌1.71%&#xff1b;两市算计成交…

uni-app调用java代码(uniapp调用安装原生插件aar)

uni-app调用java代码(uniapp调用安装原生插件aar) 文章目录 uni-app调用java代码(uniapp调用安装原生插件aar)前言一、开发环境、文档资料1.Java环境下载2.App离线SDK下载3.AndroidStudio下载4.HBuilderX下载5.uni-app扩展原生插件文档6.插件官方示例 二、将Java代码打包成aar文…

MD5、RSA 和自定义签名的 Java 数据安全实战

前言 在现代的数字世界中&#xff0c;数据的安全性和完整性变得尤为重要。为了确保数据在传输和存储过程中不受到攻击&#xff0c;我们可以借助各种加密和签名技术来加强数据安全。本文将介绍如何使用 MD5、RSA 加密&#xff0c;以及如何自定义签名规则来保护数据的安全性。下…

ISO 21202:2020 智能交通系统 - 部分自动变道系统 (PALS) - 功能/操作要求和测试规程

​ 介绍 一般来说,车辆配备的驾驶辅助系统和自动驾驶系统可减轻驾驶员的负担,有助于安全驾驶。就变道操作而言,有许多驾驶员并不擅长变道,为了辅助这类驾驶员,部分自动变道系统(PALS)可根据驾驶员的要求,在驾驶员的监督下,在禁止非机动车和行人通行、有明显车道标记的…

C#中的委托

目录 概述&#xff1a; 举例&#xff1a;​ 总结: 概述&#xff1a; 中文的角度来说:指的是把事情托付给别人或别的机构(办理)&#xff0c;造个句子&#xff1a;别人委托的事情&#xff0c;我们一定要尽力而为&#xff0c;不遗余力的去办成。 在C#中&#xff0c;委托是一种…

TCP/IP协议组

TCP/IP通信协议是目前最完整、使用最广泛的通信协议。它的魅力在于可使不同硬件结构、不同操作系统的计算机相互通信。TCP/IP协议既可用于广域网&#xff0c;也可用于局域网&#xff0c;它是Internet/Intranet的基石。TCP/IP通信协议事实上是一组协议。 TCP/IP协议可分为5层也可…

图像处理的未来:揭秘扫描全能王的AI驱动创新

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

LeetCode235. 二叉搜索树的最近公共祖先

235. 二叉搜索树的最近公共祖先 文章目录 [235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/)一、题目二、题解方法一&#xff1a;递归方法二&#xff1a;迭代 一、题目 给定一个二叉搜索树, 找到该树中两个指定…

java八股文面试——String StringBuilder StringBuffer

String类型定义&#xff1a; final String 不可以继承 final char [] 不可以修改 String不可变的好处&#xff1a; hash值只需要算一次&#xff0c;当String作为map的key时&#xff0c; 不需要考虑hash改变 天然的线程安全 知识来源&#xff1a; 【基础】String、StringB…

安卓手机录屏app合集,总有一种适合你

在现代生活中&#xff0c;录屏已经变得越来越重要。它可以帮助人们记录并分享他们的屏幕内容。在安卓手机上&#xff0c;有很多应用程序可以帮助您进行屏幕录制。本文将介绍一些最好的安卓手机录屏应用程序&#xff0c;以及一些有关录屏技巧。 录屏工具&#xff1a; 迅捷录屏大…

通达信接口开发大全(一)

通达信软件的接口开发主要可以分为以下几个方面&#xff1a; 行情接口&#xff1a;通达信提供行情订阅和实时数据查询接口&#xff0c;可以获取市场行情数据。开发者通过这些接口获取股票、期货、外汇等市场的实时行情数据&#xff0c;包括价格、成交量、买卖盘等。 交易接口&…

博弈论简介

目录 博弈分类 合作与非合作博弈&#xff1a; 同时与顺序博弈&#xff1a; 完全信息与不完全信息博弈&#xff1a; 零和与非零和博弈&#xff1a; 囚徒困境的例子 纳什平衡 代码示例 博弈论是一个数学分支&#xff0c;研究多个理性决策者之间的战略互动。它的主要目的是…

Kafka 集群搭建过程

前言 跟着尚硅谷海哥文档搭建的Kafka集群环境&#xff0c;在此记录一下&#xff0c;侵删 注意&#xff1a;博主在服务器上搭建环境的时候使用的是一个服务器&#xff0c;所以这篇博客可能会出现一些xsync分发到其他服务器时候的错误&#xff0c;如果你在搭建的过程中出现了错…