利用Dijkstra算法实现记录每个结点的所有最短路径
最近在做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算法实现记录每个结点的所有最短路径的更多相关文章
- python利用dijkstra算法求解图中最短距离
利用dijkstra算法,来完成图中两个顶点间最短的距离,可以直接复制使用,只需要修改参数即可 def dijkstra_raw(edges, from_node, to_node): "& ...
- 利用dijkstra算法规划线路
# dijkstra# 1.在数据库内预先存放了北京市内最新的道路节点,选用优化了得dijkstra算法进行线路规划. 当输入起点和终点后,会计算出最短的路径.同时还能选择查看路径经过的道路节点 ...
- 非负权值有向图上的单源最短路径算法之Dijkstra算法
问题的提法是:给定一个没有负权值的有向图和其中一个点src作为源点(source),求从点src到其余个点的最短路径及路径长度.求解该问题的算法一般为Dijkstra算法. 假设图顶点个数为n,则针对 ...
- UVA - 12661 Funny Car Racing (Dijkstra算法)
题目: 思路: 把时间当做距离利用Dijkstra算法来做这个题. 前提:该结点e.c<=e.a,k = d[v]%(e.a+e.b); 当车在这个点的1处时,如果在第一个a这段时间内能够通过且 ...
- 单源最短路径—Bellman-Ford和Dijkstra算法
Bellman-Ford算法:通过对边进行松弛操作来渐近地降低从源结点s到每个结点v的最短路径的估计值v.d,直到该估计值与实际的最短路径权重相同时为止.该算法主要是基于下面的定理: 设G=(V,E) ...
- Dijkstra算法(迪杰斯塔拉算法)
算法描述: Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法能得出最 ...
- Dijkstra算法模拟讲解
dijkstra算法,是一个求单源最短路径算法 其算法的特点为: 层层逼进,有点类似宽度搜索的感觉 其需要的数据结构为: int map[N][N] 所有点之间的权表 ...
- 单源最短路径算法——Dijkstra算法(迪杰斯特拉算法)
一 综述 Dijkstra算法(迪杰斯特拉算法)主要是用于求解有向图中单源最短路径问题.其本质是基于贪心策略的(具体见下文).其基本原理如下: (1)初始化:集合vertex_set初始为{sourc ...
- pta7-7旅游规划(dijkstra算法)
题目链接:https://pintia.cn/problem-sets/1101307589335527424/problems/1101314114762387456 题意:给n给城市,m条公路,公 ...
随机推荐
- class-map与policy-map 配置与qos模版
将subnet-a 与subnet-b 归入类class1 中.Router1(config)# ip access-list extended subnet-a Router1(config-std ...
- Go实现海量日志收集系统(四)
到这一步,我的收集系统就已经完成很大一部分工作,我们重新看一下我们之前画的图: 我们已经完成前面的部分,剩下是要完成后半部分,将kafka中的数据扔到ElasticSearch,并且最终通过kiban ...
- ignorable tips
枚举 索引从0开始 sort 默认升序排列 Array.Sort(intSort); //复制数组 Array.Copy(intSort,intNew,3); intsort 源数组 intnew ...
- Linux(Ubuntu)安装libpcap
sudo apt-get install libpcap-dev libnids-dev libnet1-dev正在读取软件包列表... 完成正在分析软件包的依赖关系树 正在读取状态信息. ...
- 关于一些基础的Java问题的解答(二)
6. Hashcode的作用 官方对于hashCode的解释如下: Whenever it is invoked on the same object more than once during an ...
- 使用Fiddler改变线上js文件的引用路径
一般的项目开发都是先在本地环境开发,测试环境中完成测试,最后再提交到线上环境. 但是由于版本构建工具有时出现bug或者一些缓存的因素导致测试环境代码可能和线上不一样,这是多么蓝瘦的事情.此处说的是在原 ...
- Jmeter_ForEach控制器实现网页爬虫
一直以来,爬虫似乎都是写代码去实现的,今天像大家介绍一下Jmeter如何实现一个网页爬虫! Jmeter的爬虫原理其实很简单,就是对网页提交一个请求,然后把返回的所有href提取出来,利用ForEac ...
- JS中的DOM— —节点以及操作
DOM操作在JS中可以说是非常常见了吧,很多网页的小功能的实现,比如一些元素的增删操作等都可以用JS来实现.那么在DOM中我们需要知道些什么才能完成一些功能的实现呢?今天这篇文章就先简单的带大家入一下 ...
- 代理delegate
1>代理的用处是什么? 监听那些不能通过addTarget监听的事件 主要用开负责在两个对象之间,发生某些事件时,传递或发送消息 当我们需要 监听某些事件时,但苹果没有提供相关监听方法(addt ...
- docker volume创建、备份、nfs存储
docker存储volume #环境 centos7.4 , Docker version 17.12.0-ce docker volume创建.备份.nfs存储 #docker volume 数据存 ...