利用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;
}
时间: 2024-10-27 19:03:05

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

利用dijkstra算法规划线路

# dijkstra# 1.在数据库内预先存放了北京市内最新的道路节点,选用优化了得dijkstra算法进行线路规划.    当输入起点和终点后,会计算出最短的路径.同时还能选择查看路径经过的道路节点附近的poi.  2.在数据库内预先存放了北京市内最新的道路节点,选用优化了得dijkstra算法进行线路规划.      当输入起点和终点后,会计算出最短的路径.同时还能选择查看路径经过的道路节点附近的poi.  3.在打包时需要重新申请一个key,不然会出现地图无法显示的错误 源码地址  htt

UVA - 12661 Funny Car Racing (Dijkstra算法)

题目: 思路: 把时间当做距离利用Dijkstra算法来做这个题. 前提:该结点e.c<=e.a,k = d[v]%(e.a+e.b); 当车在这个点的1处时,如果在第一个a这段时间内能够通过且更小的话,那时间就更新为d[e.to] = d[v]+e.a-k+e.c; 当车在这个点的1处时,如果在第一个a这段时间内不能通过,但等待之后再通过时间更短的话,那时间更新为d[e.to]=d[v]+e.a+e.b-k+e.to 如果在这个点的2处时,如果在等待之后通过的时间更短的话,时间更新和第二种情况

第25章:所有结点对的最短路径问题—floyd-warshall和Johnson算法

二:Floyd-Warshall算法 该算法适用于边权重可以为负值,但环路权重和不能为负值的图,其运行时间为Θ(V3). 假设dkij为从结点i到结点j的所有中间结点全部取自集合{1,2,-,k}的一条最短路径权重.当k=0时,从结点i到结点j的一条不包括编号大于0的中间结点的路径将没有任何中间结点.这样的路径最多只有一条边,因此d(0)ij=wij.因此如果k=0,dkij=wij,若k>=1,则dkij=min(d(k?1)ij,d(k?1)ik+d(k?1)kj). 另外,我们可以在计算最

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

算法描述: Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低. Dijkstra算法是很有代表性的最短路算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等. 其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合.一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知.

python 实现dijkstra算法求解最短路径

? 重点:dijkstra算法按层计算其余点到源点的最短距离,层层扩展. 1. dijkstra算法 求解目标:找到图中源点到其余点的最短距离,是单源点最短距离算法. 整体思路:每一步都寻找到与源点最近的点,层层扩展,是贪心算法. 具体实现: 输入:给定一个图的邻接表M,源点u. 辅助变量:存储与源点最短距离的字典.存储已访问节点的集合. 算法过程: 初始化:将源点加入已访问集合 对已访问集合中每个点的所有邻接点,计算与源点的最短距离存入字典和已访问集合. 重复2,直至所有顶点被访问 2. 求解

最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)

一,问题描述 在英文单词表中,有一些单词非常相似,它们可以通过只变换一个字符而得到另一个单词.比如:hive-->five:wine-->line:line-->nine:nine-->mine..... 那么,就存在这样一个问题:给定一个单词作为起始单词(相当于图的源点),给定另一个单词作为终点,求从起点单词经过的最少变换(每次变换只会变换一个字符),变成终点单词. 这个问题,其实就是最短路径问题. 由于最短路径问题中,求解源点到终点的最短路径与求解源点到图中所有顶点的最短路径复

进阶实验6-3.2 社交网络图中结点的“重要性”计算 (30分)-dijkstra算法

解题思路:(邻接矩阵存储) 用dijkstra算法依次求出每个结点到其余结点的最短距离 #include <stdio.h> #include <string.h> #define INF 0x3f3f3f3f #define MaxVex 1000+10 int G[MaxVex][MaxVex]; int visit[MaxVex]; int Nv,Ne; void Init() { memset(G,INF,sizeof(G)); int i; for(i=1; i<=

43. 蛤蟆的数据结构笔记之四十三最短路径之迪杰斯特拉(Dijkstra )算法

43. 蛤蟆的数据结构笔记之四十三最短路径之迪杰斯特拉(Dijkstra )算法 本篇名言:"辛勤的蜜蜂永没有时间悲哀.--布莱克" 这次来看下Dijkstra )算法.还是老方法,先原理,后实现.代码来自网络. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47046031 1.  最短路径 最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径. 管道铺设.线路安排

单源最短路径(dijkstra算法)php实现

做一个医学项目,其中在病例评分时会用到单源最短路径的算法.单源最短路径的dijkstra算法的思路如下: 如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点.那么(Vi...Vk)也必定是从i到k的最短路径.Dijkstra是以最短路径长度递增,逐次生成最短路径的算法.例如:对于源顶点V0,首先选择其直接相邻的顶点中长度最短的顶点Vi,那么当前已知可得从V0到达Vj顶点的最短距离dist[j]=min{dist[j],dist[i]+cost[i][j]}.假设G