【算法入门&图论】【模板】拓扑排序|【模板】单源最短路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月前
|
机器学习/深度学习 人工智能 算法
深度学习入门:理解神经网络与反向传播算法
【9月更文挑战第20天】本文将深入浅出地介绍深度学习中的基石—神经网络,以及背后的魔法—反向传播算法。我们将通过直观的例子和简单的数学公式,带你领略这一技术的魅力。无论你是编程新手,还是有一定基础的开发者,这篇文章都将为你打开深度学习的大门,让你对神经网络的工作原理有一个清晰的认识。
|
3月前
|
算法
【算法】前缀和——二维前缀和模板题
【算法】前缀和——二维前缀和模板题
|
1月前
|
机器学习/深度学习 算法
机器学习入门(三):K近邻算法原理 | KNN算法原理
机器学习入门(三):K近邻算法原理 | KNN算法原理
|
1月前
|
机器学习/深度学习 算法 大数据
机器学习入门:梯度下降算法(下)
机器学习入门:梯度下降算法(下)
|
1月前
|
机器学习/深度学习 算法 API
机器学习入门(五):KNN概述 | K 近邻算法 API,K值选择问题
机器学习入门(五):KNN概述 | K 近邻算法 API,K值选择问题
|
1月前
|
算法 决策智能
基于prim算法求出网络最小生成树实现网络社团划分和规划
该程序使用MATLAB 2022a版实现路线规划,通过排序节点权值并运用Prim算法生成最小生成树完成网络规划。程序基于TSP问题,采用遗传算法与粒子群优化算法进行路径优化。遗传算法通过编码、选择、交叉及变异操作迭代寻优;粒子群优化算法则通过模拟鸟群觅食行为,更新粒子速度和位置以寻找最优解。
|
1月前
|
机器学习/深度学习 算法
机器学习入门:梯度下降算法(上)
机器学习入门:梯度下降算法(上)
|
3月前
|
机器学习/深度学习 人工智能 算法
AI入门必读:Java实现常见AI算法及实际应用,有两下子!
本文全面介绍了人工智能(AI)的基础知识、操作教程、算法实现及其在实际项目中的应用。首先,从AI的概念出发,解释了AI如何使机器具备学习、思考、决策和交流的能力,并列举了日常生活中的常见应用场景,如手机助手、推荐系统、自动驾驶等。接着,详细介绍了AI在提高效率、增强用户体验、促进技术创新和解决复杂问题等方面的显著作用,同时展望了AI的未来发展趋势,包括自我学习能力的提升、人机协作的增强、伦理法规的完善以及行业垂直化应用的拓展等...
182 3
AI入门必读:Java实现常见AI算法及实际应用,有两下子!
|
4月前
|
机器学习/深度学习 数据采集 人工智能
机器学习算法入门与实践
【7月更文挑战第22天】机器学习算法入门与实践是一个既充满挑战又极具吸引力的过程。通过掌握基础知识、理解常见算法、注重数据预处理和模型选择、持续学习新技术和参与实践项目,你可以逐步提高自己的机器学习技能,并在实际应用中取得优异的成绩。记住,机器学习是一个不断迭代和改进的过程,保持好奇心和耐心,你将在这个领域走得更远。
|
3月前
|
存储 算法
【C算法】编程初学者入门训练140道(1~20)
【C算法】编程初学者入门训练140道(1~20)