最近在做PAT时发现图论的一些题目需要对多条最短路径进行筛选,一个直接的解决办法是在发现最短路径的时候就进行判断,选出是否更换路径;另一个通用的方法是先把所有的最短路径记录下来,然后逐个判断。前者具有一定的难度并且不好排查BUG,因此我设计了一种基于Dijkstra的记录所有最短路的简捷算法,用于解决此类题目。

我们知道,Dijkstra是解决单源最短路问题的,并且最基本的算法仅能求出最短路的长度,而不能输出路径,本文基于Dinjkstra进行改进,使之能记录源点到任意点的所有最短路径。

使用vector<int>来记录一条路径,因为每个结点可能有多条最短路径,因此把这些路径都装在一个vector中,因此可以用一个vector<vector<int> >来表示一个结点的所有最短路径,把所有结点的最短路径都存放起来,又需要一个vector容器,因此所有结点的所有最短路径的集合可以用vector<vector<vector<int>
> >来表示。

约定:结点编号为0到N-1,源点为0,到每个点的最短距离存储在数组minD[N]中。

在Dijkstra算法初始化时,找出所有源点的邻接点w并且把相应的最短距离minD[w]更新,同时初始化这些点w的第一条最短路径0->w(实现方法为分别push_back 0和w)。接下来将会找到一个到源点最短的点v,并且把v并入集合,对v的所有未访问的邻接点,如果到达w的路径(0->...->w)在包含v之后(0->...->v->w)变短,则删除w之前所有的最短路径,并且更新为到v的所有最短路径加上w点(注意对每个到v的最短路径都要这样处理);如果到达w的路径在包含v之后长度不变,说明发现了一条新的最短路径,在w原来最短路径容器的基础上再压入一个新的最短路径,这条路径为所有到v的最短路径加上w点。

经过这样的运算,就可以得到所有结点的所有最短路径了,下面以一个实例对算法进行测试,并且附上源代码。

题目:求下图的源点0到所有结点的最短路径。

输入:

5 8

2 4 1

0 1 3

0 2 6

1 3 2

1 4 1

3 4 1

3 2 1

0 4 4

输出:

源码为:

#include <iostream>
#include <stdio.h>
#include <vector> using namespace std; #define MAX 1001
#define INF 99999999 int G[MAX][MAX];
int minD[MAX];
int minDist;
int finalSet[MAX]; int main()
{
int N,M;
int v1,v2;
int len;
cin >> N >> M;
for(int i = 0; i < N; i++){
finalSet[i] = 0;
minD[i] = INF;
for(int j = 0; j < N; j++)
G[i][j] = INF;
}
for(int i = 0; i < M; i++){
scanf("%d%d%d",&v1,&v2,&len);
G[v1][v2] = G[v2][v1] = len;
} vector<vector<vector<int> > > nodes(N); // 设0为源点,计算从0到所有点的所有最短路径
finalSet[0] = 1;
minD[0] = 0;
// 首先把所有源点邻接点的最短距离初始化为源点到这些点的距离
for(int i = 1; i < N; i++){
if(G[0][i] != INF) {
minD[i] = G[0][i];
vector<vector<int> > minPaths;
minPaths.clear();
vector<int> pathList;
pathList.clear();
pathList.push_back(0);
pathList.push_back(i);
minPaths.push_back(pathList);
nodes[i] = minPaths;
}
} // 从所有minD中找出最小的,并入集合S,重复N-1次(源点已经加入集合)
for(int i = 1; i < N; i++){
minDist = INF;
int v = -1; // 记录到源点记录最小的结点
for(int w = 1; w < N; w++){
if(!finalSet[w] && minDist > minD[w]){
minDist = minD[w];
v = w;
}
}
if(v == -1) break; // v = -1说明找不到点了,当图不连通时才会出现这种情况
// 已经找到了到源点最近的点v,将其并入集合,并且考虑原来的最短距离0->...->W在加入了v之后有没有可能变短
// 如果变短了,就更新为0->...>v->W
finalSet[v] = 1;
for(int w = 1; w < N; w++){
if(!finalSet[w]){
int newD = minDist + G[v][w];
if(newD < minD[w]){
minD[w] = newD;
vector<vector<int> > minPathsV = nodes[v];
vector<int> pathList;
nodes[w].clear();
for(int index = 0; index < minPathsV.size(); index++){
pathList = minPathsV[index];
pathList.push_back(w);
nodes[w].push_back(pathList);
} }else if(newD == minD[w]){ vector<vector<int> > minPathsV = nodes[v];
vector<int> pathList;
for(int index = 0; index < minPathsV.size(); index++){
pathList = minPathsV[index];
pathList.push_back(w);
nodes[w].push_back(pathList);
} }
}
}
}
for(int i = 1; i < N; i++){
cout << "------------" << endl;
cout << "0 to "<< i << ":" << endl;
cout << "The miniest distance:" << endl << minD[i] << endl;
cout << "The possible paths:" << endl;
vector<vector<int> >minPaths = nodes[i];
int size = minPaths.size();
vector<int> pathList;
for(int j = 0; j < size; j++){
pathList = minPaths[j];
int pathSize = pathList.size();
for(int k = 0; k < pathSize - 1; k++){
cout << pathList[k] << "->";
}
cout << pathList[pathSize - 1] << endl;
} } return 0;
}

利用Dijkstra算法实现记录每个结点的所有最短路径的更多相关文章

  1. python利用dijkstra算法求解图中最短距离

    利用dijkstra算法,来完成图中两个顶点间最短的距离,可以直接复制使用,只需要修改参数即可 def dijkstra_raw(edges, from_node, to_node): "& ...

  2. 利用dijkstra算法规划线路

    # dijkstra# 1.在数据库内预先存放了北京市内最新的道路节点,选用优化了得dijkstra算法进行线路规划.    当输入起点和终点后,会计算出最短的路径.同时还能选择查看路径经过的道路节点 ...

  3. 非负权值有向图上的单源最短路径算法之Dijkstra算法

    问题的提法是:给定一个没有负权值的有向图和其中一个点src作为源点(source),求从点src到其余个点的最短路径及路径长度.求解该问题的算法一般为Dijkstra算法. 假设图顶点个数为n,则针对 ...

  4. UVA - 12661 Funny Car Racing (Dijkstra算法)

    题目: 思路: 把时间当做距离利用Dijkstra算法来做这个题. 前提:该结点e.c<=e.a,k = d[v]%(e.a+e.b); 当车在这个点的1处时,如果在第一个a这段时间内能够通过且 ...

  5. 单源最短路径—Bellman-Ford和Dijkstra算法

    Bellman-Ford算法:通过对边进行松弛操作来渐近地降低从源结点s到每个结点v的最短路径的估计值v.d,直到该估计值与实际的最短路径权重相同时为止.该算法主要是基于下面的定理: 设G=(V,E) ...

  6. Dijkstra算法(迪杰斯塔拉算法)

    算法描述: Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法能得出最 ...

  7. Dijkstra算法模拟讲解

    dijkstra算法,是一个求单源最短路径算法 其算法的特点为: 层层逼进,有点类似宽度搜索的感觉 其需要的数据结构为:                  int map[N][N] 所有点之间的权表 ...

  8. 单源最短路径算法——Dijkstra算法(迪杰斯特拉算法)

    一 综述 Dijkstra算法(迪杰斯特拉算法)主要是用于求解有向图中单源最短路径问题.其本质是基于贪心策略的(具体见下文).其基本原理如下: (1)初始化:集合vertex_set初始为{sourc ...

  9. pta7-7旅游规划(dijkstra算法)

    题目链接:https://pintia.cn/problem-sets/1101307589335527424/problems/1101314114762387456 题意:给n给城市,m条公路,公 ...

随机推荐

  1. Linux查看系统版本号及关机命令各种方法归纳

    shutdown -h now 立即关机halt 立即关机init 0 立即关机poweroff 立即关机shutdown -r now 重启reboot 重启logout 注销su - 命令切换身份 ...

  2. 如何避免 async/await 地狱

    简评:async/await 写着很爽,不过要注意这些问题. async/await 让我们摆脱了回调地狱,但是这又引入了 async/await 地狱的问题. 什么是 async/await 地狱 ...

  3. text-size-adjust: none并没有什么用

    在样式文件中添加text-size-adjust: none,并没有什么用,移动端浏览器自动调整字体大小还是在进行,webkit已取消对其支持,移动端避免浏览器因为横屏.竖屏模式自动缩放字体大小可以加 ...

  4. Kafka,Mq,Redis作为消息队列使用时的差异?

    redis 消息推送(基于分布式 pub/sub)多用于实时性较高的消息推送,并不保证可靠.其他的mq和kafka保证可靠但有一些延迟(非实时系统没有保证延迟).redis-pub/sub断电就清空, ...

  5. Java常用排序算法

    在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序. 一般来说外排序分为两个步骤:预处理和合并排序.首先,根据可用内存的大小,将外存上含有n个纪录的文件分成若干长 ...

  6. Go 语言 goto 语句

    Go 语言的 goto 语句可以无条件地转移到过程中指定的行. goto语句通常与条件语句配合使用.可用来实现条件转移, 构成循环,跳出循环体等功能. 但是,在结构化程序设计中一般不主张使用goto语 ...

  7. MySQL PHP 语法

    MySQL PHP 语法 MySQL 可应用于多种语言,包括 PERL, C, C++, JAVA 和 PHP. 在这些语言中,MySQL在PHP的web开发中是应用最广泛. 在本教程中我们大部分实例 ...

  8. RTMPdump(libRTMP)源代码分析 4: 连接第一步——握手(Hand Shake)

    ===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...

  9. java开源即时通讯软件服务端openfire源码构建

    java开源即时通讯软件服务端openfire源码构建 本文使用最新的openfire主干代码为例,讲解了如何搭建一个openfire开源开发环境,正在实现自己写java聊天软件: 编译环境搭建 调试 ...

  10. Git之(四)分支管理

    当我们初始化Git仓库的时候,Git会默认创建一个名为master的主分支.在实际工作中,主分支要求是一个稳定.健壮.安全的主线,一般不允许在主分支上直接进行开发,而是拉取一个新的分支,开发.测试完成 ...