算法 - 图的实例 - 最短路径 (Shortest Path)

SPFA最短路径 路径记录 做了一道板子题,求v0点到任意点的最短距离和最短路径这里用SPFA,记录一下#include <bits/stdc++.h> #define MAXN 500005 using namespace std; typedef long long ll; struct Edge{ ll next, weight; Edge(ll _next, ll _weig... 阅读详情

算法 - 图的实例 - 最短路径 (Shortest Path)

返回分类:全部文章 >> 基础知识

返回上级:编程基础 - 图 (Graph)

本文将介绍最短路径的基础知识,并用C++实现迪杰斯特拉算法(Dijkstra)和弗洛伊德算法(Floyed)。

在查看本文之前,需要一些数据结构和程序语言的基础。

尤其是“矩阵”、“矩阵的压缩(matrix)”、“图(graph)”等的知识。



1 最短路径简述 (Introduction)

最短路径问题是找到一个顶点到另一个顶点之间权值之和最小的路径。

  • 一个顶点称为源点

  • 另一个顶点称为终点

其图是有向带权图。


2 迪杰斯特拉算法 (Dijkstra)

迪杰斯特拉算法 (Dijkstra) 适用于:

  • (1)源点只有一个;

  • (2)权值必须都是大于等于零。

2.1 算法基本思想 (Basic Idea)

Dijkstra算法意指按照路径长度的递增次序,逐步的产生最短路径。

  • (1)首先、求出长度最短的一条最短路径;

  • (2)其次,参照它求出长度次短的一条最短路径;

  • (3)最后,重复步骤(2)直到求出所有最短路径。

假设原图,起始点A:

10
50
30
90
10
20
70
99
A
B
C
D
E
F

其从A开始到达各个点的权值,取最小值就是路径:

到达点\经过边数 1 2 3
B AB(10)
C ABC(60), ADC(50)
D AD(30)
E AE(90) ADE(100) ABCE(70), ADCE(60)
F

2.2 算法设计思路 (Design Idea)

其算法描述:

  • 假设 n 个顶点, e 条边的图,求得最短路径的集合为 P, 顶点为 { v0, v1, … , vn }, 权值和的数组为 cost[n]。
    • (1)初始化: P = { v0 } , cost[vadj] = Edge[v0][vadj] ;(adj为邻接顶点)
    • (2)获取最短路径,并添加顶点: cost[vmin] = min(cost) , P = { v0, vmin } ;
    • (3)更新路径长度与路径:cost[vminadj] = min(cost[vminadj], cost[vmin] + Edge[vmin][vminadj]) ;
    • (4)重复步骤(2)和(3):直到所有顶点检测完成。

其 n 个顶点的图,时间复杂度 O(n2) 。

2.3 C++代码 (C++ Code)

// Author: https://blog.youkuaiyun.com/DarkRabbit
// Shortest Path
// 迪杰斯特拉算法
// params:
//      graph:      需要计算的图
//      begin:      起始顶点
//      paths:      输出的顺序
//      costs:      输出的权值和
// return:
//      bool:       是否出错
bool Dujkstra(AMGraphInt* graph, 
              int begin, 
              std::vector<std::vector<int>>& paths, 
              std::vector<double>& costs)
{
   
   
    if (graph == nullptr || !graph->IsOriented()) // 无向图返回
    {
   
   
        return false;
    }

    int size = graph->GetVertexCount(); // 顶点数量
    if (begin < 0 || begin >= size) // 起始点不在图中,直接返回
    {
   
   
        return false;
    }

    double infinity = graph->GetDefaultWeight(); // 没有边的权值,即正无穷
    paths.assign(size, std::vector<int>()); // 初始化空路径
    costs.assign(size, infinity); // 初始化权值和
    std::vector<bool> marks(size, false); // 顶点标记(集合)

    // 起始顶点
    costs[begin] = 0;
    marks[begin] = true;
    paths[begin].push_back(begin);

    // 初始化costs,从起始点开始到达的首个顶点
    double weight = 0;
    for (int adj = graph->FirstNeighbor(begin); 
             adj != -1; 
             adj = graph->NextNeighbor(begin, adj))
    {
   
   
        graph->TryGetWeight(begin, adj, weight);
        paths[adj].push_back(begin); // begin 加入到 adj 的路径
        costs[adj] = weight;
    }

    // 循环,路径最多需要加入 size - 1 个顶点
    for (int i = 1; i < size; i++)
    {
   
   
        int minVertex = -1; // 选出未访问过的,cost最小的顶点
        double minCost = infinity; // 选出的最小cost

        // 选出未访问过的,cost最小的顶点
        for (int j = 0; j < size; j++)
        {
   
   
            // 如果顶点没有访问过,且cost更小
            if (!marks[j] && costs[j] < minCost)
            {
   
   
                minVertex = j;
                minCost = costs[j];
            }
        }

        if (minVertex == -1) // 未选出顶点,说明其它顶点无法到达
        {
   
   
            break;
        }

        marks[minVertex] = true; // 访问此顶点
        paths[minVertex].push_back(minVertex); // 加入路径

        // 查找minVertex的邻接顶点,并更新路径和cost
        for (int adj = graph->FirstNeighbor(minVertex);
                 adj != -1;
                 adj = graph->NextNeighbor(minVertex, adj))
        {
   
   
            graph->TryGetWeight(minVertex, adj, weight);
            
            // 如果新cost更小,则更新,新cost = 到达上一个顶点的cost + 到达此顶点的 cost
            if (!marks[adj] && costs[minVertex] + weight < costs[adj])
            {
   
   
                costs[adj] = costs[minVertex] + weight; // 更新cost
                paths[adj].clear();
                paths[adj].insert(paths[adj].begin(),
                                  paths[minVertex].begin(),
                                  paths[minVertex].end()); // 更新路径
            }
        }
    }

    return true;
}

3 弗洛伊德算法 (Floyed)

弗洛伊德算法 (Floyed) 相比较于 迪杰斯特拉算法 (Dijkstra) 它:

  • (1)可以有多个源点;

  • (2)权值可以是负数,但负数权值不能组成回路。

  • (3)复杂度更高。

3.1 算法基本思想 (Basic Idea)

对有 n n n 个顶点, e e e 条边,权值为 ( e i j ) n × n (e_{ij})_{n \times n} (eij​)n×n​ 的图:

  • (1)它是通过一个 n n n 阶方阵求出每两点间的最短路径,即

    A = { A ( 0 ) , A ( 1 ) , ⋯ &ThinSpace; , A ( n ) } A = \{ A^{(0)}, A^{(1)}, \cdots, A^{(n)} \} A={ A(0),A(1),⋯,A(n)}

    其中:
    A ( 0 ) = ( a i j ) n × n ( 0 ) , ( a i j ) ( 0 ) = e i j A ( k ) = ( a i j ) n × n ( k ) , ( a i j ) ( k ) = min ⁡ { ( a i j ) ( k − 1 ) , ( a i k ) ( k − 1 ) + ( a k j ) ( k − 1 ) } , k ∈ [ 1 , n ] \begin{aligned} A^{(0)} &amp;=(a_{ij})^{(0)}_{n \times n}, &amp;(a_{ij})^{(0)} &amp;=e_{ij} \\ A^{(k)} &amp;=(a_{ij})^{(k)}_{n \times n}, &amp;(a_{ij})^{(k)} &amp;= \min \{(a_{ij})^{(k-1)}, (a_{ik})^{(k-1)} + (a_{kj})^{(k-1)}\}, &amp; k \in [1, n] \end{aligned} A(0)A(k)​=(aij​)n×n(0)​,=(aij​)n×n(k)​,​(aij​)(0)(aij​)(k)​=eij​=min{ (aij​)(k−1),(aik​)(k−1)+(akj​)(k−1)},​k∈[1,n]​

  • (2) ( a i j ) ( 0 ) (a_{ij})^{(0)} (aij​)(0) 是从顶点 v i v_i vi​ 到 v j v_j vj​ ,以 v 0 v_0 v0​ 为中介的最短路径长度;

  • (3) ( a i j ) ( k ) (a_{ij})^{(k)} (aij​

邻接表实现 单源最短路径SPFA算法 poj1511 首先讲邻接表的实现,以前一直遇到题目都是用vector模拟,今天遇到一个题目vector超时,于是学习了用数组模拟实现邻接表,新学的数据结构,搞的不是很透彻,记录一下。 其实就是头插发,首先用一个结构体E记录节点的信息,指向那个节点,以及指向节点的权值等信息,给E结构体设置一个next,让它指向H数组,H数组初始化为-1,初始化为-1是为了方便判断某个点直接相连点是否找完了,自己还不是很透彻了, 阅读详情

相关推荐

最短路(SPFA算法)讲解+例题

SPFA 算法介绍 SPFA 算法是 Bellman-Ford算法的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA 最坏情况下复杂度和朴素 Bellman-Ford 相同,为 O(VE)。 算法的思路: (转自https://blog.youkuaiyun.com/qq_35644234/article/details/61614581)     我们用数组dis记录每个...

WQN20172674的博客 2035

最短路径算法实例

一个最短路径算法实例,并包装成文件的输入和输出,需要输入的数据位于in.dat文件,计算结果保存在out.dat文件中

WinForm多语言切换实战:5分钟搞定中英文界面(附完整代码)

本文提供了WinForm应用实现中英文界面切换的两种高效实战方案。通过利用内置的本地化机制和资源文件,开发者可以在5分钟内为窗体添加多语言支持,并附有完整代码示例,帮助快速应对软件国际化需求。

weixin_29230773的博客 406

Ubuntu20.04安装Eigen3.3.7、模板类Sophus和Ceres

Sophus的使用必须依赖3.3以上的Eigen版本。如果版本太低,Sophus库将无法安装使用。

qq_62964142的博客 3422

告别反复格式化!用Ventoy制作2025年终极启动盘,Windows/Linux/macOS一网打尽

本文详细介绍了如何使用Ventoy制作2025年终极多系统启动盘,彻底告别反复格式化U盘的烦恼。Ventoy通过创新的引导加载器架构,允许用户在一个U盘内同时存放并直接启动Windows、Linux、macOS等多种系统镜像和WePE等维护工具,实现真正的非破坏性管理和极高的U盘利用率。文章涵盖从安装配置、镜像库构建到安全启动设置等全流程实战指南。

weixin_29280219的博客 242

告别瞎猜!用通达信L2资金流向函数,手把手教你识别主力动向(附实战公式)

本文详细解析通达信L2资金流向函数,手把手教你构建主力动向监控系统。通过分档数据解析、委买委卖攻防解读及实战公式应用,帮助投资者精准识别主力建仓与虚假拉升信号,提升股票交易决策效率。

weixin_26908317的博客 2096

计算机视觉——SIFT特征匹配

文章目录一、SIFT特征检测原理1.1基本思想1.2二、SIFT特征检测图片兴趣点三、SIFT特征检测描述子匹配四、输入图片检测与之 一、SIFT特征检测原理 1.1基本思想 1.2 二、SIFT特征检测图片兴趣点 代码: 检测结果: 三、SIFT特征检测描述子匹配 四、输入图片检测与之 ...

weixin_43869874的博客 3855

Android Audio常见问题分析方法

分析audio dump,确定写给BT的data是否正常,MTK平台Android原生架构分析threadloop write节点,高通平台分析QXDM 1586节点,从dump确定问题大概位置。分析systrace 确定性能。AudioFocus状态(用于播放或者音量异常的情况)。AudioTrack是否正常创建bt连接是否正常通路异常,setMode,setSpeakerphoneOn等都会影响设备选择,sco调用流程是否正常。

一条老狗的博客 2389

视觉提示学习(Prompt Learning):CV领域的GPT时刻?

视觉提示学习(Prompt Learning):CV领域的GPT时刻? ,人工智能,计算机视觉,大模型,AI,在人工智能技术不断演进的今天,计算机视觉(Computer Vision,CV)作为人工智能领域的重要分支,始终致力于让机器 “看懂” 世界。从早期基于传统特征工程的图像识别方法,到深度学习时代卷积神经网络(Convolutional Neural Networks,CNN)的崛起,CV 领域经历了多次重大变革。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 4万+

【第33话:车辆控制】自动驾驶车辆运动学模型推导及详解

自动驾驶车辆的运动学模型以自行车模型为核心,通过状态方程。

一碗白开水一 832

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

上一篇: 算法 - 图的实例 - 最小生成树 (Minimum Spanning Tree)
下一篇: 算法 - 图的实例 - 拓扑排序与关键路径 (Topological Sort and Critical Path)
沙沙的兔子
博客等级 码龄17年 359粉丝 135原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值