【算法入门&图论】【模板】拓扑排序|【模板】单源最短路2 |最小生成树(下)

简介: 【算法入门&图论】【模板】拓扑排序|【模板】单源最短路2 |最小生成树

2、AB14 最小生成树

题目链接:最小生成树


ef33f317f7c543bcb4e23a6d067afb09.png


2.1、解题思路

本题要求在最小花费下将 n 户人家连接起来,很显然是最小生成树的问题,我采用prim算法:


将二维数组cost按权升序排序,那么cost[0][2]就是最小的一个权值

将连接这条边的两个顶点放入unordered_set容器:

unordered_set 容器的元素是无序的,可以用来给顶点去重

内置的 find 方法也很好用

接下来遍历cost二维数组,直到所有顶点全部放入容器中,遍历结束

将遍历中权值的和返回,程序结束

2.2、代码实现与注释

本题源码:

class Solution {
  public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 返回最小的花费代价使得这n户人家连接起来
     * @param n int n户人家的村庄
     * @param m int m条路
     * @param cost intvector<vector<>> 一维3个参数,表示连接1个村庄到另外1个村庄的花费的代价
     * @return int
     */
    // 自定义排序规则:按权递增
    static bool cmp(vector<int>& x, vector<int>& y) {
        return x[2] < y[2];
    }
    int miniSpanningTree(int n, int m, vector<vector<int> >& cost) {
        unordered_set<int> points; // 记录不重复的点
        int res = 0;
        sort(cost.begin(), cost.end(), cmp);
        res += cost[0][2]; // 此时res 为最小权值
        // 将最小边加入
        points.insert(cost[0][0]);
        points.insert(cost[0][1]);
        while (1) {
            if (points.size() == n)
                break; // 所有的点连同后退出循环
            // 遍历剩余的边
            for (auto it = cost.begin(); it != cost.end(); it++) {
                // 如果边仅有一个点在集合内就加入
                if ((points.find((*it)[0]) != points.end() &&
                    points.find((*it)[1]) == points.end()) ||
                    (points.find((*it)[1]) != points.end() &&
                    points.find((*it)[0]) == points.end()))
                    {
                        res += (*it)[2];
                        points.insert((*it)[0]);
                        points.insert((*it)[1]);
                        cost.erase(it); // 删除该边
                        break;
                    }
            }
        }
        return res;
    }
};

重要注释:


cmp 是自定义的一个按权递增的排序函数,配合sort函数来将cost排序

相关知识点可以参考我的博文:自定义排序规则

auto关键字可以自动推导表达式类型,在这里就相当于vector<vector<int>>::iterator

if的条件很长,但其实就是将有且仅有一个顶点在points中的边找到:

获取该边的权值并求和,将另一顶点插入到points 中

将该边删除,重新遍历cost,直到全部顶点被插入到points中

最终的 res 就是该题的结果,即最小花费。

3、AB15 单源最短路2

题目链接:单源最短路2

9794408295f4486f98c87be1c595da6b.png

3.1、解题思路

使用Dijkstra算法(即不断从未处理集合中找当前距离源点最近的顶点以添加到已处理集合中,直至未处理集合为空的算法思想)


对于无向图,采用邻接矩阵表示点与点的连接关系以及距离

使用数组dist记录每个顶点与源点的距离:

本题中就是记录顶点1与其他顶点的距离

用一个布尔类型的数组记录顶点的处理情况:

初始状态全部设为false,一经处理就设为true

最终dist[n]就是顶点n到源点的最短距离

3.2、代码实现与注释

本题源码

#include<iostream>
#include<climits> // 使用INT_MAX所需要引入的头文件
using namespace std;
const int N = 5000; // 注意题干,图的点数是固定值5000
int main() {
    int G[N + 1][N + 1]; // 用于模拟邻接矩阵进行建图
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            G[i][j] = INT_MAX; // 先将邻接矩阵全部初始化为无穷大
        }
    }
    int n, m;
    cin >> n >> m;
    int u, v, w;
    for (int i = 1; i <= m; i++) {
        cin >> u >> v >> w;
        G[u][v] = w;
        G[v][u] = w; // 需要关于主对角线对称,因此两边都需要存储
    }
    int dist[N + 1]; // 用于存储每个顶点当前与源点的最短距离
    bool flag[N + 1]; // 用于记录每个顶点是否已经完成与源点最短距离的计算处理
    for (int i = 1; i <= N; i++) {
        dist[i] = G[1][i]; // 初始设置为邻接矩阵中源点所在 行 的权值
        flag[i] = false;
    }
    dist[1] = 0;
    flag[1] = true; // 将源点加入已处理集合
    for (int i = 2; i <= N; i++) {
        int tmp = INT_MAX, index = 1;
        for (int j = 1; j <= N; j++) { // 遍历寻找与源点的最短距离
            if (flag[j] == false && dist[j] < tmp) {
                tmp = dist[j];
                index = j;
            }
        }
        if (index != 1) {
            flag[index] = true; // 找到后将其加入已处理集合
        }
        for (int j = 2; j <= N; j++) {
            if (flag[j] == false && G[index][j] != INT_MAX) {
                if (G[index][j] + dist[index] < dist[j]) {
                    dist[j] = G[index][j] + dist[index]; // 更新最短路径
                }
            }
        }
    }
    if (dist[n] != INT_MAX) {
        cout << dist[n];
    } else {
        cout << -1;
    }
    return 0;
}

重要注释:


二维数组G是具化出的邻接矩阵,将元素值全部初始化为无穷大:INT_MAX

u,v记录两个顶点,w记录顶点间距离,全部存入G中

dist数组用来存放各顶点到源点的距离,flag数组记录顶点是否被处理过

index代表着与源点连接且距离最短的未经处理的顶点:

随后将该顶点设为已处理

然后index寻找与之相连且未经处理的顶点:

dist[index]是index到源点的最短距离,如果加上与之相连的顶点的距离较小,那么就更新最短路径

最终的dist数组的值就是各点到源点的最短路径


目录
相关文章
|
2月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
161 7
|
2月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
133 8
|
2月前
|
JSON 算法 数据挖掘
基于图论算法有向图PageRank与无向图Louvain算法构建指令的方式方法 用于支撑qwen agent中的统计相关组件
利用图序列进行数据解读,主要包括节点序列分析、边序列分析以及结合节点和边序列的综合分析。节点序列分析涉及节点度分析(如入度、出度、度中心性)、节点属性分析(如品牌、价格等属性的分布与聚类)、节点标签分析(如不同标签的分布及标签间的关联)。边序列分析则关注边的权重分析(如关联强度)、边的类型分析(如管理、协作等关系)及路径分析(如最短路径计算)。结合节点和边序列的分析,如子图挖掘和图的动态分析,可以帮助深入理解图的结构和功能。例如,通过子图挖掘可以发现具有特定结构的子图,而图的动态分析则能揭示图随时间的变化趋势。这些分析方法结合使用,能够从多个角度全面解读图谱数据,为决策提供有力支持。
117 0
|
2月前
|
机器学习/深度学习 算法 Python
机器学习入门:理解并实现K-近邻算法
机器学习入门:理解并实现K-近邻算法
43 0
|
3月前
|
算法 搜索推荐 Java
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
基数排序是一种稳定的排序算法,通过将数字按位数切割并分配到不同的桶中,以空间换时间的方式实现快速排序,但占用内存较大,不适合含有负数的数组。
48 0
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
|
3月前
|
机器学习/深度学习 算法 大数据
机器学习入门:梯度下降算法(下)
机器学习入门:梯度下降算法(下)
|
3月前
|
算法
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
38 0
|
3月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
87 0
|
5天前
|
算法 数据安全/隐私保护
室内障碍物射线追踪算法matlab模拟仿真
### 简介 本项目展示了室内障碍物射线追踪算法在无线通信中的应用。通过Matlab 2022a实现,包含完整程序运行效果(无水印),支持增加发射点和室内墙壁设置。核心代码配有详细中文注释及操作视频。该算法基于几何光学原理,模拟信号在复杂室内环境中的传播路径与强度,涵盖场景建模、射线发射、传播及接收点场强计算等步骤,为无线网络规划提供重要依据。
|
6天前
|
机器学习/深度学习 数据采集 算法
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目基于MATLAB2022a实现时间序列预测,采用CNN-GRU-SAM网络结构。卷积层提取局部特征,GRU层处理长期依赖,自注意力机制捕捉全局特征。完整代码含中文注释和操作视频,运行效果无水印展示。算法通过数据归一化、种群初始化、适应度计算、个体更新等步骤优化网络参数,最终输出预测结果。适用于金融市场、气象预报等领域。
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真