最小生成树刷题笔记

2024-05-13 00:44
文章标签 笔记 最小 生成 树刷题

本文主要是介绍最小生成树刷题笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

算法基础:

最小生成树是所有节点的最小连通子图!!!!

首先是prim算法三部曲:

(1)找到距离最小生成树最近的节点。

(2)将距离最小生成树最近的节点加入到最小生成树中。

(3)更新非最小生成树节点到最小生成树的距离。

实现步骤:

首先我们利用一个for循环遍历n - 1遍,因为我们从第1个节点开始将其加入到生成树之中后知道添加到还剩两个节点时,我们可以发现当我们添加玩倒数第二个节点后,最后一个节点的mindist数值在处理倒数第二个节点的第三部更新过程中已经得到了,这个距离不是倒数第二个节点到它的距离grid[cur][j]就是之前已经得到的它与某个节点之间的距离mindist[j]。

(1)寻找最近节点:

判断最近节点的三个条件:1.未在生成树中。  2.距离生成树距离最短     3.选取最短距离我们先随便选出一个节点然后再与其他节点比较

if(!isvisited[j] && (cur = -1 || mindist[cur] > mindist[j])              Cur = j;

这里:Mindist[cur] < mindist[j]包含了两层含义:首先我们要明确我们要找离生成树距离最短的点,mindist数组中存的只就是节点到生成树的最小距离,如果后续的节点的mindist的值要小于前面得出的mindist值,那么就将当前节点的标记j赋值给cur。

这里我们每遍历一层就会将cur置为-1以便我们可以最快选取一个随机节点并遍历后面的节点与之比较。而第二层的mindist[j]的值已经在第一层的第三步更新操作中得到。

(2)将最近节点加入生成树:

isintree[cur] = true;

(3)更新非生成树节点到生成树距离:

利用一个for循环遍历所以非生成树节点,并更新起距离mindist[j] < grid[cur][j] ? Mindist[j] = mindist[j] : mindist[j] = grid[cur][j]

这列的更新操作有两层意思:第一是遍历的外部节点需要与生成树有连接,也就是grid[cur][j] < mindist[j] == INT_MAX,第二是当前节点已经跟生成树有连接但还没选入进入生成树(预备党员哈哈)因为之前节点的更新扩散操作使得与之前节点有连接的j节点有了mindist的数值,所以我们拿grid[cur][j]与之前得到的最近距离mindist作比较保留更小的那个值赋值给mindist[j]

经过上面的分析,我认为prim算法的关键一定是要明确mindist数组的含义:是当前节点到最小生成树的最小距离。因为我们的第一步选点用到mindist数组来根据各个点到生成树(第一步时就是到源点的距离)的最小距离来选取最近节点,我们的第三步更新也是由于新加入的点导致未加入节点到生成树的距离改变,通过grid[cur][j] 与mindist[j]来判断是否需要更改mindist的值。

#include<iostream>
#include<vector>
using namespace std;
int main() {
    int v, e;
    int x, y, k;
    cin >> v >> e;
    // 填一个默认最大值,题目描述val最大为10000
    vector<vector<int>> grid(v + 1, vector<int>(v + 1, 10001));
    while (e--) {
        cin >> x >> y >> k;
        // 因为是双向图,所以两个方向都要填上
        grid[x][y] = k;
        grid[y][x] = k;

    }
    // 所有节点到最小生成树的最小距离
    vector<int> minDist(v + 1, 10001);

    // 这个节点是否在树里
    vector<bool> isInTree(v + 1, false);

    // 我们只需要循环 n-1次,建立 n - 1条边,就可以把n个节点的图连在一起
    for (int i = 1; i < v; i++) {

        // 1、prim三部曲,第一步:选距离生成树最近节点
        int cur = -1; // 选中哪个节点 加入最小生成树
        for (int j = 1; j <= v; j++) { // 1 - v,顶点编号,这里下标从1开始
            //  选取最小生成树节点的条件:
            //  (1)不在最小生成树里
            //  (2)距离最小生成树最近的节点
            //  (3)只要不在最小生成树里,先默认选一个节点 ,在比较 哪一个是最小的
            //  理解条件3 很重要,才能理解这段代码:(cur == -1 || minDist[j] < minDist[cur])
            if (!isInTree[j] && (cur == -1 || minDist[j] < minDist[cur])) {
                cur = j;
            }
        }
        // 2、prim三部曲,第二步:最近节点(cur)加入生成树
        isInTree[cur] = true;

        // 3、prim三部曲,第三步:更新非生成树节点到生成树的距离(即更新minDist数组)
        // cur节点加入之后, 最小生成树加入了新的节点,那么所有节点到 最小生成树的距离(即minDist数组)需要更新一下
        // 由于cur节点是新加入到最小生成树,那么只需要关心与 cur 相连的 非生成树节点 的距离 是否比 原来 非生成树节点到生成树节点的距离更小了呢
        for (int j = 1; j <= v; j++) {
            // 更新的条件:
            // (1)节点是 非生成树里的节点
            // (2)与cur相连的某节点的权值 比 该某节点距离最小生成树的距离小
            // 很多录友看到自己 就想不明白什么意思,其实就是 cur 是新加入 最小生成树的节点,那么 所有非生成树的节点距离生成树节点的最近距离 由于 cur的新加入,需要更新一下数据了
            if (!isInTree[j] && grid[cur][j] < minDist[j]) {
                minDist[j] = grid[cur][j];
            }
        }
    }
    // 统计结果
    int result = 0;
    for (int i = 2; i <= v; i++) { // 不计第一个顶点,因为统计的是边的权值,v个节点有 v-1条边
        result += minDist[i];
    }
    cout << result << endl;

}

leetcode - 1584:连接所有点的最小费用

由于这道题给出的是点集,我们可以想到使用prim来处理点集的最小生成树问题,这道题不好使用kruskal来解决因为还要求边那就需要我们去求各个点的组合会复杂很多。

就是利用题目中的公式建立邻接矩阵在套用上面的模板即可:

class Solution {
public:
    int minCostConnectPoints(vector<vector<int>>& points) {
        int n = points.size();
        vector<vector<int>> grid(n, vector<int>(n, 0));
        // 计算任意两点之间的曼哈顿距离并填充到grid矩阵中
        for(int i = 0; i < n; i++){
            for(int j = i + 1; j < n; j++){
                int x = abs(points[i][0] - points[j][0]);
                int y = abs(points[i][1] - points[j][1]);
                grid[i][j] = grid[j][i] = x + y;
            }
        }
        vector<bool> isvisited(n, false);
        vector<int> mindist(n, INT_MAX);
        mindist[0] = 0; // 从第一个点开始
        int res = 0;
        for(int i = 0; i < n - 1; i++){
            int cur = -1;
            // 选择当前距离生成树最近的节点
            for(int j = 0; j < n; j++){
                if(!isvisited[j] && (cur == -1 || mindist[j] < mindist[cur])){
                    cur = j;
                }
            }
            isvisited[cur] = true;
            // 更新其他节点到生成树的距离
            for(int j = 0; j < n; j++){
                if(!isvisited[j] && mindist[j] > grid[cur][j]){
                    mindist[j] = grid[cur][j];
                }
            }
        }
        for(int i = 1; i < n; i++){
            res += mindist[i];
        }
        return res;
    }

这篇关于最小生成树刷题笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/984209

相关文章

浅析如何使用Swagger生成带权限控制的API文档

《浅析如何使用Swagger生成带权限控制的API文档》当涉及到权限控制时,如何生成既安全又详细的API文档就成了一个关键问题,所以这篇文章小编就来和大家好好聊聊如何用Swagger来生成带有... 目录准备工作配置 Swagger权限控制给 API 加上权限注解查看文档注意事项在咱们的开发工作里,API

Java使用POI-TL和JFreeChart动态生成Word报告

《Java使用POI-TL和JFreeChart动态生成Word报告》本文介绍了使用POI-TL和JFreeChart生成包含动态数据和图表的Word报告的方法,并分享了实际开发中的踩坑经验,通过代码... 目录前言一、需求背景二、方案分析三、 POI-TL + JFreeChart 实现3.1 Maven

MybatisGenerator文件生成不出对应文件的问题

《MybatisGenerator文件生成不出对应文件的问题》本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成... 目录MyBATisGenerator 文件生成不出对应文件先在项目结构里引入“targetProje

Python使用qrcode库实现生成二维码的操作指南

《Python使用qrcode库实现生成二维码的操作指南》二维码是一种广泛使用的二维条码,因其高效的数据存储能力和易于扫描的特点,广泛应用于支付、身份验证、营销推广等领域,Pythonqrcode库是... 目录一、安装 python qrcode 库二、基本使用方法1. 生成简单二维码2. 生成带 Log

Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南

《Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南》在日常数据处理工作中,我们经常需要将不同Excel文档中的数据整合到一个新的DataFrame中,以便进行进一步... 目录一、准备工作二、读取Excel文件三、数据叠加四、处理重复数据(可选)五、保存新DataFram

SpringBoot生成和操作PDF的代码详解

《SpringBoot生成和操作PDF的代码详解》本文主要介绍了在SpringBoot项目下,通过代码和操作步骤,详细的介绍了如何操作PDF,希望可以帮助到准备通过JAVA操作PDF的你,项目框架用的... 目录本文简介PDF文件简介代码实现PDF操作基于PDF模板生成,并下载完全基于代码生成,并保存合并P

详解Java中如何使用JFreeChart生成甘特图

《详解Java中如何使用JFreeChart生成甘特图》甘特图是一种流行的项目管理工具,用于显示项目的进度和任务分配,在Java开发中,JFreeChart是一个强大的开源图表库,能够生成各种类型的图... 目录引言一、JFreeChart简介二、准备工作三、创建甘特图1. 定义数据集2. 创建甘特图3.

AI一键生成 PPT

AI一键生成 PPT 操作步骤 作为一名打工人,是不是经常需要制作各种PPT来分享我的生活和想法。但是,你们知道,有时候灵感来了,时间却不够用了!😩直到我发现了Kimi AI——一个能够自动生成PPT的神奇助手!🌟 什么是Kimi? 一款月之暗面科技有限公司开发的AI办公工具,帮助用户快速生成高质量的演示文稿。 无论你是职场人士、学生还是教师,Kimi都能够为你的办公文

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n