Dijkstra算法求最短路径 c++

news2024/11/18 3:39:28

目录

【问题背景】

【相关知识】

【算法思想】

【算法实现】

【伪代码】

【输入输出】

【代码】


【问题背景】

出门旅游,有些城市之间有公路,有些城市之间则没有,如下图。为了节省经费以及方便计划旅程,希望在出发之前知道城市之间的最短路程。

 上图中有4个城市8条公路,公路上的数字表示这条公路的长短。请注意这些公路是单向的。

我们想知道指定一个城市(源点)到其余各个城市的最短路程,也叫做“单源最短路径”。

【相关知识】

求带权有向图最短路径问题分为两种情况:求从一个顶点到其他各顶点的最短路径,称之为单源最短路径问题;求每对顶点之间的最短路径,称之为多源最短路径问题。

求单源最短路径算法是由狄克斯特拉(Dijkstra)提出的,称为狄克斯特拉算法,是一个按路径长度递增的顺序逐步产生最短路径的方法。

【算法思想】

给定一个图G和一个起始顶点即源点v,求v到其他顶点的最短路径长度及最短路径。

① 初始时,顶点集S只包含源点,即S={v0​},顶点v0​到自已的距离为0。顶点集T包含除v0​外的其他顶点,源点v0​T中顶点i的距离为边上的权(若v0​i有边<v0​,i>)或(若顶点i不是v0​的出边相邻点)。

② 从T中选取一个顶点u,它是源点v0​U中距离最小的一个顶点,然后把顶点u加入S中(该选定的距离就是源点v0​到顶点u的最短路径长度)。

③ 以顶点u为新考虑的中间点,修改源点v0​U中各顶点j(j∈T)的距离。

重复步骤②和③直到S包含所有的顶点即T为空。

【算法实现】

  1. 设置一个数组dist[0..n-1]dist[i]用来保存从源点v0​到顶点i的目前最短路径长度。

  2. path[j]保存源点到顶点j的最短路径,实际上为最短路径上的前一个顶点u,即path[j]=u

  3. 当求出最短路径后由path[j]向前推出源点到顶点j的最短路径。

举例,有如下有向图,求从0到其余顶点的最短路径:

下表给出了上述有向网G中从源点0到其余各顶点的最短路径的求解过程。

最后求出顶点01~6各顶点的最短距离分别为4、5、6、10、916

以求顶点0到顶点4的最短路径为例说明通过path求最短路径的过程:

path[4]=5,path[5]=2,path[2]=1,path[1]=0(源点), 则顶点0到顶点4的最短路径逆为4、5、2、1、0,则正向最短路径为0→1→2→5→4

【伪代码】

  1. 初始化数组dist、path和s;
  2. while (s中的元素个数<n) 2.1 在dist[n]中求最小值,其下标为k; 2.2 输出dist[j]和path[j]; 2.3 修改数组dist和path; 2.4 将顶点vk添加到数组s中;

根据上面的伪代码用邻接矩阵实现Dijkstra算法。

【输入输出】

第一行输入顶点和边的个数vertexNum和arcNum

第二行输入各个顶点的值,为字符型

下面arcNum行依次输入边的起点编号,终点编号和权值

【测试数据】

请输入顶点个数和边的个数:5 6

请输入顶点的值A B C D E

依次输入边的起点编号,终点编号和权值

0 1 1

0 3 1

0 4 1

2 4 1

3 4 1

3 2 1

请输入起始顶点:A

输出从A到各个顶点的最短路径:

从A到B顶点的最短路径长度为:1

从A到B顶点的最短路径为:A->B

从A到C顶点的最短路径长度为:2

从A到C顶点的最短路径为:A->D->C

从A到D顶点的最短路径长度为:1

从A到D顶点的最短路径为:A->D

从A到E顶点的最短路径长度为:1

从A到E顶点的最短路径为:A->E

注意没有路径的情况

请输入顶点个数和边的个数:5 7

请输入顶点的值A B C D E

依次输入边的起点编号,终点编号和权值

0 1 10

0 3 30

0 4 100

1 2 50

2 4 10

3 4 60

3 2 20

请输入起始顶点:B

输出从B到各个顶点的最短路径:

从B到A没有路径.

从B到C顶点的最短路径长度为:50

从B到C顶点的最短路径为:B->C

从B到D没有路径.

从B到E顶点的最短路径长度为:60

从B到E顶点的最短路径为:B->C->E

【代码】

#include<iostream>
#include<algorithm>
#include<string>
#include<limits.h>
using namespace std;
const int MAX_V_NUM = 100;
template <class T>
struct EdgeType
{
    T from, to;     //边依附的两个顶点
    int weight;      //边上的权值
};

template <class T>
class EdgeGraph
{
private:
    char vertex[MAX_V_NUM] = { 0 };  //存放图顶点的数组
    int arc[MAX_V_NUM][MAX_V_NUM] = { INT_MAX };
    int vexNum, arcNum;         //图的顶点数和边数
    int s[MAX_V_NUM] = { 0 };  //存储顶点是否被查找过
    int start;  //输入的起始顶点下标
public:
    EdgeGraph(int vNum, int eNum);
    void Dijkstra();
    int findMinDist(int* dist);  //在dist中查找s[i]为0的最小值元素
    int getIndex(char v)
    {
        for (int i = 0; i < vexNum; i++) {
            if (vertex[i] == v) {
                return i;
            }
        }
        return -1; // 如果找不到顶点,返回-1
    }
    void displayPath(int* dist, int* path);
};
template <class T>
EdgeGraph<T>::EdgeGraph(int vNum, int eNum)
{
    int u, v, w;
    vexNum = vNum;
    arcNum = eNum;

    //arc初始化
    for (int i = 0; i < vexNum; i++)
    {
        for (int j = 0; j < vexNum; j++)
        {
            if (i != j)
                arc[i][j] = INT_MAX;
            else
                arc[i][j] = 0;
        }
    }
    cout << "请输入顶点的值";
    for (int i = 0; i < vexNum; i++)
    {
        cin >> vertex[i];
    }
    cout << "依次输入边的起点编号,终点编号和权值\n";
    for (int i = 0; i < arcNum; i++)
    {
        cin >> u >> v >> w;
        arc[u][v] = w;
    }
    cout << "请输入起始顶点:";
    char c;
    cin >> c;
    start = getIndex(c);
}

//迪杰斯特拉
template <class T>
void EdgeGraph<T>::Dijkstra()
{
    int dist[MAX_V_NUM] = { INT_MAX };
    int path[MAX_V_NUM] = { -1 };
    int num = 0; //记录顶点数
    int min;//记录最小值

    for (int i = 0; i < vexNum; i++)
    {
        dist[i] = arc[start][i];
        if (dist[i] != INT_MAX)
            path[i] = start;
        else
            path[i] = -1;
    }

    //s数组的初始化
    for (int i = 0; i < vexNum; i++)
    {
        s[i] = 0;
    }
    s[start] = 1;//顶点放入集合s。
    num = 1;
    while (num < vexNum) //当顶点数小于图的顶点数
    {
        min = findMinDist(dist); //找到最小值
        for (int i = 0; i < vexNum; i++)
        {    //更新dist和path
            if ((s[i] == 0) && (dist[min] + arc[min][i] < dist[i]) && dist[min] != INT_MAX && arc[min][i] != INT_MAX)  //找到更短的距离,防止距离为无穷的情况
            {             
                dist[i] = dist[min] + arc[min][i];
                path[i] = min; 
            }
        }
        s[min] = 1; //将新生成的点加入s
        num++;
    }
    //打印输出起始点到各顶点的最短路径
    displayPath(dist, path);
}

//找最小值
template <class T>
int EdgeGraph<T>::findMinDist(int* dist)
{
    int min = INT_MAX;
    int index = -1;
    for (int i = 0; i < vexNum; i++) //在dist数组中没有生成树(s[i]=0)的结点中查找
    {
        if (s[i] == 0)
        {
            if (dist[i] < min)
            {
                min = dist[i];
                index = i;
            }
        }
    }
    return index;
}

//输出路径
template <class T>
void EdgeGraph<T>::displayPath(int* dist, int* path)
{
    char result[MAX_V_NUM] = { 0 };
    int k = 0;
    cout << "输出从" << vertex[start] << "到各个顶点的最短路径:\n";
    for (int i = 0; i < vexNum; i++)
    {
        if (i != start)
        {
            if (dist[i] <= 0 || dist[i] == INT_MAX)
            {
                cout << endl;
                cout << "从" << vertex[start] << "到" << vertex[i] << "没有路径." << endl;
            }
            else
            {
                cout << endl;
                cout << "从" << vertex[start] << "到" << vertex[i] << "顶点的最短路径长度为:" << dist[i] << endl;
                cout << "从" << vertex[start] << "到" << vertex[i] << "顶点的最短路径为:" << vertex[start];
                int j = i;
                while (j != start)
                {
                    result[k++] = vertex[j];
                    j = path[j];
                }
                for (int l = k - 1; l >= 0; l--)
                {
                    cout << "->" << result[l];
                }
                k = 0;  //将k归0,进行下一次路径记录
                cout << endl;
            }
        }
    }
    cout << endl;
}

int main()
{
    int vNum, eNum;
    cout << "请输入顶点个数和边的个数:";
    cin >> vNum >> eNum;
    EdgeGraph<char> graph(vNum, eNum);
    graph.Dijkstra();
    return 0;
}

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

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

相关文章

集合、Collection接口特点和常用方法

1、集合介绍 对于保存多个数据使用的是数组&#xff0c;那么数组有不足的地方。比如&#xff0c; 长度开始时必须指定&#xff0c;而且一旦制定&#xff0c;不能更改。 保存的必须为同一类型的元素。 使用数组进行增加/删除元素的示意代码&#xff0c;也就是比较麻烦。 为…

必应bing国内广告开户首充和开户费是多少?

微软必应Bing作为国内领先的搜索引擎之一&#xff0c;其广告平台凭借其精准的投放、高效的数据分析和广泛的用户覆盖&#xff0c;已成为众多企业的首选。 根据最新政策&#xff0c;2024年必应Bing国内广告开户预充值金额设定为1万元人民币起。这一调整旨在确保广告主在账户初始…

奥德彪的幸福VS码农的幸福

奥德彪的幸福 非洲国家布隆迪是一个全球最不发达国家之一&#xff0c;大部分居民以农业为生&#xff0c;其中包括香蕉&#xff0c;人们拿香蕉用来做饭也用来酿酒。 香蕉产地距离布隆迪首都布琼布拉很远&#xff0c;而这个国家又缺乏规模化的物流企业&#xff0c;于是就诞生了…

如何用java做一个模拟登录画面

要求&#xff1a; 实现registerAction方法中的注册逻辑。实现login方法中的登录逻辑&#xff0c;确保只有当用户名和密码都正确时才返回true。实现好友管理功能&#xff0c;包括添加好友、删除好友、查看好友列表。确保所有的文件操作&#xff08;如读取和写入credentials.txt…

Java类

一.什么是类&#xff1f; 在src文件夹下面用一个Text类&#xff0c;这个Text就是这一个类的类名&#xff0c;所以说&#xff0c;一个Java文件里面就存在一个类&#xff0c;&#xff08;在Java中有一个习惯&#xff0c;一个Java文件里面&#xff0c;只写一个类&#xff09;。 &…

SSMP整合案例第三步 业务层service开发及基于Mybatis的接口功能拓展

业务层开发 对于业务层的制作有个误区 Service层接口定义与数据层接口定义具有较大差别 不要混用 业务层接口关注的是业务名称 数据层接口关注的是数据层名称 操作是不难 但是有些东西还是要掌握的 业务层接口如果是业务方法 就按照业务名称来代替 如果是数据操作 直接用…

pytorch文本分类(四)模型框架(模型训练与验证)

关卡四 模型训练与验证 本文是在原本闯关训练的基础上总结得来&#xff0c;加入了自己的理解以及疑问解答&#xff08;by GPT4&#xff09; 原任务链接 目录 关卡四 模型训练与验证1. 训练1.1 构建模型结构1.2 模型编译1.3 模型训练1.4模型超参数调试 2. 推理2.1 模型准确性…

UDP协议与TCP协议1.2

UDP UDP数据报UDP报头UDP载荷 UDP的报文格式&#xff1a; 这里的UDP长度&#xff0c;描述了整个UDP数据报&#xff0c;占多少个字节&#xff0c;这里整个UDP长度最多是64kb 在UDP中校验和就是使用CRC的方式来完成的 数据在网络传输中是可能会出现错误的&#xff0c;例如比特翻…

四信云-设备维保管理系统上线,实现设备全生命周期管理

在当今的制造业中&#xff0c;设备是企业生产的核心要素&#xff0c;是企业竞争力的基石。 随着企业发展规模不断扩大&#xff0c;设备数量急速增长&#xff0c;传统的手工管理方式已经无法满足企业需求&#xff0c;设备管理系统的出现则填补了市场需求空白&#xff0c;其目标…

翻译《The Old New Thing》- How do I mark a shortcut file as requiring elevation?

How do I mark a shortcut file as requiring elevation? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20071219-00/?p24103 Raymond Chen 2007年12月19日 如何将快捷方式标记为需要提升权限 简要 文章介绍了如何通过设置SLDF_RUNAS_US…

echarts-坐标轴2

刻度的间隔 类目轴的间隔 interval xAxis: {type: "category",name: "x轴",axisLine: {},axisLabel: {show: true,color: "yellow",backgroundColor: "blue",interval: 5,},data: [11, 22, 322, 422, 522, 622, 722, 822, 229, 1220,…

k8s集群安装后CoreDNS 启动报错plugin/forward: no nameservers found

安装k8s过程中遇到的问题&#xff1a; 基本信息 系统版本&#xff1a;ubuntu 22.04 故障现象&#xff1a; coredns 报错&#xff1a;plugin/forward: no nameservers found 故障排查&#xff1a; #检查coredns的配置&#xff0c;发现有一条转发到/etc/resolv.conf的配置…

哪些类型的产品适合用3D形式展示?

随着3D技术的蓬勃发展&#xff0c;众多品牌和企业纷纷投身3D数字化浪潮&#xff0c;将产品打造成逼真的3D模型进行展示&#xff0c;消费者可以更加直观地了解产品的特点和优势&#xff0c;从而做出更明智的购买决策。 哪些产品适合3D交互展示&#xff1f; 产品3D交互展示具有直…

云计算事件响应优秀实践

云计算如今已经成为一种主流技术&#xff0c;随着云安全的日益普及&#xff0c;他们正在与德迅云团队合作&#xff0c;致力于开始保护其云计算系统。 云计算如今已经成为一种主流技术&#xff0c;几乎所有组织都在公有云中运行一些资源——无论是网站、游戏、app、小程序。德迅…

钡铼BL205分布式IO在精密机械加工自动化中的精准控制OPC UA

随着工业自动化技术的不断发展&#xff0c;精密机械加工领域对于高效、精准的控制需求日益增加。在这一背景下&#xff0c;钡铼BL205分布式IO的出现为精密机械加工自动化注入了新的活力和可能性。本文将探讨钡铼BL205分布式IO在精密机械加工自动化中的应用&#xff0c;尤其是其…

LeetCode算法题:42. 接雨水(Java)

题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3…

c4d云渲染是工程文件会暴露吗?

在数字创意产业飞速发展的今天&#xff0c;C4D云渲染因其高效便捷而备受欢迎。然而&#xff0c;随着技术应用的深入&#xff0c;人们开始关注一个核心问题&#xff1a;在享受云渲染带来的便利的同时&#xff0c;C4D工程文件安全吗&#xff1f;是否会有暴露的风险&#xff1f;下…

企业微信主体机构如何修改?

企业微信变更主体有什么作用&#xff1f; 做过企业运营的小伙伴都知道&#xff0c;很多时候经常会遇到现有的企业需要注销&#xff0c;切换成新的企业进行经营的情况&#xff0c;但是原来企业申请的企业微信上面却积累了很多客户&#xff0c;肯定不能直接丢弃&#xff0c;所以这…

【安装笔记-20240523-Windows-安装测试 ShareX】

安装笔记-系列文章目录 安装笔记-20240523-Windows-安装测试 ShareX 文章目录 安装笔记-系列文章目录安装笔记-20240523-Windows-安装测试 ShareX 前言一、软件介绍名称&#xff1a;ShareX主页官方介绍 二、安装步骤测试版本&#xff1a;16.1.0下载链接功能界面 三、应用场景屏…

Jenkins安装 :AWS EC2 Linux

1 JDK11 install # 用的yum安装 # 压缩包安装&#xff0c;下载的jdk-11.0.22_linux-x64_bin.tar.gz在EC2解压&#xff0c;配置环境变量&#xff0c;运行jenkins的时候会报错$ yum -y list java-11* Available Packages java-11-amazon-corretto-devel.x86_64 …