最近在做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. 背景重复样式background-repeat

    一.background-repeat属性 在CSS中,使用background-repeat属性可以设置背景图像是否平铺,并且可以设置如何平铺. 语法: background-repeat:取值; ...

  2. ExecutorService

    接口 java.util.concurrent.ExecutorService 表述了异步执行的机制,并且可以让任务在后台执行.壹個 ExecutorService 实例因此特别像壹個线程池.事实上, ...

  3. javascript实现图片的预览

    简单javascript代码 实现上传图片预览 <body> <!-- 设置当有图片准备上传时触发javascript代码--> <input type="fi ...

  4. Linux c readdir是非线程安全,需用readdir_r,要注意用静态变量当做返回值的函数的非线程安全性

    readdir函数: struct dirent *readdir(DIR *dirp); The  data  returned by readdir() may be overwritten by ...

  5. URL重定向漏洞,python打造URL重定向漏洞检测脚本

    前言: 今天学习了重定向漏洞,这个漏洞比较好理解 漏洞名:URL重定向漏洞 威胁:低 漏洞的来源:开发者对head头做好对应的过滤和限制 例子: 有漏洞的网站:http://a.com/x.php?u ...

  6. 全新 Kali Linux 系统安装指南

    Kali Linux 系统可以说是在安全测试方面最好的开箱即用的 Linux 发行版.Kali 下的很多工具软件都可以安装在大多数的 Linux 发行版中,Offensive Security 团队在 ...

  7. PHP XML SimpleXML

    PHP 可以基于 SimpleXML 生成和解析 xml 的方法,通过本节的实例,你将了解 PHP 是如何使用 SimpleXML 生成及解析 xml 格式数据的. PHP SimpleXML 处理最 ...

  8. 导出和导入Docker容器

    导出容器 如果要导出本地某个容器,可以使用 docker export 命令. $ sudo docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATU ...

  9. 用Netty解析Redis网络协议

    用Netty解析Redis网络协议 根据Redis官方文档的介绍,学习了一下Redis网络通信协议.然后偶然在GitHub上发现了个用Netty实现的Redis服务器,很有趣,于是就动手实现了一下! ...

  10. 【SSH系列】一步步深入springmvc+商品列表查询demo

    在前面的博文中,小编主要简单的介绍springmvc的体系结构.mvc模式的优缺点以及mvc框架,今天我们来继续学习springmvc的相关知识,在这篇博文中,小编讲解过springmvc的体系结构, ...