有向图中单个源点到终点的最短路径--Dijkstra算法与实现

1、Dijkstra算法能够解决有向图中单个源点到另一终点的最短路径问题,它的算法过程如下:

1)用矩阵graph[]N[N](N为图中节点个数)表示带权的有向图G。若图中两个节点vi和vj是连通的,则graph[i][j]表示这两个节点之间边的权值;若两节点vi和vj不是连通的,则graph[i][j] = -1.

2)设S为从某点start_vec开始的最短路径path的终点集合,初始状态时,集合S中只有起始节点start_vec.设从起始节点start_vec到其余节点vi的最短路径长度为D[i]. 设剩余节点集合remanderLis,它表示未被选中的剩余节点,初始状态remanderLis 包含除起始节点start_vec之外图中任一节点。

3)对于非起始节点vi,初始化D[i] = graph[start_vec][i].

4)从remanderLis中选择一个节点,该节点是由起始节点经过当前已选中节点能够到达的节点中路径最短的节点,方法是比较当前的D数组D[j],从中选出最小的值D[j]且满足S中没有节点vj. 设选中的节点为min_vec, 将min_vec加入集合S中,并从集合remanderLis中删除节点min_vec.

5)修改从起始节点start_vec到任一剩余节点vk(集合remanderLis)的最短路径长度D[k]。若节点vk与min_vec之间有边,则视情况更新D[k],若D[k] == -1,即start_vec到vk没有边,D[k] = D[min_vec] + graph[min_vec][k];若D[k] != -1,则判段  D[k] = min{D[k], D[min_vec] + graph[min_vec][k]};

6)重复4到5过程,直到remanderLis集合为空。

2、下面给出图片说明(参考别人的)

从运算过程表中,我们可知v0到其余个点的最短路径,如下图

3、下面给出代码实现,我们知道Dijkstra算法肯定要输出源点到终点的路径,下面的算法中将会实现,简单说明就是在每次更新D[K]的时候更新数组pathArr,pathArr[k]用于存储由起始节点到节点vk最短路径上vk的上一个节点,当从起始节点到终点的路径过程中,每一个非起始节点都会存储它的上一个节点,所以只要从终点节点开始,遍历pathArr数组就可以找到从起始节点到终点的路径。本算法实现还有一个特殊的地方是采用-1来表示两个节点之间无边,你可能会好奇这样设置,到时找最小边的时候怎么办,任何有边的两点之间的权值都会大于-1,这能行吗?答案肯定的,下面的算法实现中会展现出来。好了,no
bb, show you code.

#include <iostream>
#include <list>
#include <vector>
#include <stack>
#include <climits>
using namespace std;

#define N 6

int graph[N][N] = /*{-1, -1, 10, -1, 30, 100,
                    -1, -1, 5, -1, -1, -1,
                    -1, -1, -1, 50, -1, -1,
                    -1, -1, -1, -1, -1, 10,
                    -1, -1, -1, 20, -1, 60,
                    -1, -1, -1, -1, -1, -1 };*/
                    { -1, 10, 12, -1, -1, -1,
                      -1, -1, -1, 16, 25, -1,
                      4, 3, -1, 12, -1, 8,
                      -1, -1, -1, -1, 7, -1,
                      -1, -1, -1, -1, -1, -1,
                      -1, -1, -1, 2, 10, -1
                    };

void dijkstra_algorithm(int graphArcs[][N], int start_vec, int end_vec)
{
    int D[N] = {0};              //从起始点到其他点的最短路径,初始化为0
    int selectedVecs[N] = {0};
    selectedVecs[start_vec] = 1;            //开始只有起始节点被选中,其他节点未被选中
    vector<int> pathVecs;        //在起始点到终点的最短路径过程中,vector[i]存储节点i的上一个节点
    list<int> remanderLis;       //剩余的节点集合
    int i;
    for(i = 0; i < N; i++)
    {
        if(i == start_vec)
            continue;
        remanderLis.push_back(i);
        D[i] = graphArcs[start_vec][i];           //初始情况下初始节点到其他节点的最短路径长度
        //cout << D[i] << " ";
        pathVecs.push_back(start_vec);              //初始时候,将每个节点的上一个节点初始化为起始节点
    }
    //cout << endl;
    while(!remanderLis.empty())         //没有剩余节点后或找到终点路径,则退出循环
    {
        int j, minVec;
        unsigned int minArc = UINT_MAX;  //这里定义无符号整形的作用是方便和-1比较,无符号整数 < -1
        for(j = 0; j < N; j++)           //从未被选中的剩余节点中,找出距离起始节点最近的节点
        {
            if(selectedVecs[j] != 0)
                continue;
            if(minArc > D[j])               //当D[j]=-1时,表示节点j与起始点之间没有路径,且无符号整形与-1比较时,-1更大
            {
                minArc = D[j];
                minVec = j;
            }
        }
        if(selectedVecs[minVec] == 0)
        {
            selectedVecs[minVec] = 1;         //在未被选中的点中距离起始节点最近的点将被选中
            remanderLis.remove(minVec);     //删除已经被选中的节点
        }
        if(selectedVecs[end_vec] == 1)      //若选中了end_vec,则退出循环
            break;
        //选人新节点后,更新D[]数组
        for(j = 0; j < N; j++)
        {
            if(selectedVecs[j] != 0)
                continue;                           //已被选中节点则跳过
            if(graphArcs[minVec][j] != -1)          //选中节点和各个节点直接有路径
            {
                if(D[j] == -1)            //起始节点到节点j没有路径
                    D[j] = D[minVec] + graphArcs[minVec][j];
                else if(D[j] > D[minVec] + graphArcs[minVec][j])
                    D[j] = D[minVec] + graphArcs[minVec][j];
                pathVecs[j] = minVec;
            }
        }
    }
    if(D[end_vec] == -1)
    {
        cout << "sorry, can't find the path from " << start_vec << " to " << end_vec << endl;
        return;
    }
    cout << "the path length from " << start_vec << " to " << end_vec << " is: " << D[end_vec] << endl;
    cout << "the path form " << start_vec << " to " << end_vec << " is: ";
    //vector<int>::iterator iter = pathVecs.rbegin();
    stack<int> pathS;
    pathS.push(end_vec);
    i = end_vec;
    do
    {
        pathS.push(pathVecs[i]);
        i = pathVecs[i];
    }while(i != start_vec);

    while(!pathS.empty())
    {
        cout << pathS.top() << " ";
        pathS.pop();
    }
}

int main()
{
    dijkstra_algorithm(graph, 0, 4);

    return 0;
}

运行结果如下:

是不是挺简单的。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-04 10:09:34

有向图中单个源点到终点的最短路径--Dijkstra算法与实现的相关文章

有向网络(带权的有向图)的最短路径Dijkstra算法

什么是最短路径? 单源最短路径(所谓单源最短路径就是只指定一个顶点,最短路径是指其他顶点和这个顶点之间的路径的权值的最小值) 什么是最短路径问题? 给定一带权图,图中每条边的权值是非负的,代表着两顶点之间的距离.指定图中的一顶点为源点,找出源点到其它顶点的最短路径和其长度的问题,即是单源最短路径问题. 什么是Dijkstra算法? 求解单源最短路径问题的常用方法是Dijkstra(迪杰斯特拉)算法.该算法使用的是贪心策略:每次都找出剩余顶点中与源点距离最近的一个顶点. 算法思想 带权图G=<V,

数据结构:单源最短路径--Dijkstra算法

Dijkstra算法 单源最短路径 给定一带权图,图中每条边的权值是非负的,代表着两顶点之间的距离.指定图中的一顶点为源点,找出源点到其它顶点的最短路径和其长度的问题,即是单源最短路径问题. Dijkstra算法 求解单源最短路径问题的常用方法是Dijkstra(迪杰斯特拉)算法.该算法使用的是贪心策略:每次都找出剩余顶点中与源点距离最近的一个顶点. 算法思想 带权图G=<V,E>,令S为已确定了最短路径顶点的集合,则可用V-S表示剩余未确定最短路径顶点的集合.假设V0是源点,则初始 S={V

最短路径-Dijkstra算法(转载)

注意:以下代码 只是描述思路,没有测试过!! Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等.注意该算法要求图中不存在负权边. 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到

最短路径—Dijkstra算法

Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等.注意该算法要求图中不存在负权边. 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径.(单源最短路径) 2.算法

求两点之间最短路径-Dijkstra算法

 Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等.注意该算法要求图中不存在负权边. 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径.(单源最短路径) 2.算

最短路径-Dijkstra算法与Floyd算法

一.最短路径 ①在非网图中,最短路径是指两顶点之间经历的边数最少的路径. AE:1    ADE:2   ADCE:3   ABCE:3 ②在网图中,最短路径是指两顶点之间经历的边上权值之和最短的路径. AE:100   ADE:90   ADCE:60   ABCE:70 ③单源点最短路径问题 问题描述:给定带权有向图G=(V, E)和源点v∈V,求从v到G中其余各顶点的最短路径. 应用实例--计算机网络传输的问题:怎样找到一种最经济的方式,从一台计算机向网上所有其它计算机发送一条消息. ④每

单源最短路径Dijkstra算法

1.单源最短路径 函数:返回还未被收录顶点中dist最小者 1 Vertex FindMinDist(MGraph Graph, int dist[], int collected[]) 2 { 3 /*返回未被收录顶点中dist最小者*/ 4 Vertex MinV, V; 5 int MinDist = INFINITY; 6 7 8 for (V = 0; V < Graph->Nv; ++V) 9 { 10 if (collected[V] == false && di

有向图中,每对结点之间最短路径

1.有向图中,每对结点之间的最短路径 动态规划法:向前处理法:由前向后递推的方式求解列出的关系式 本题关键在于: A[i][j]= A[i][j] < (A[i][k]+A[k][j]) ? A[i][j] : A[i][k]+A[k][j]; 即A(i,j)=min{A(i,j), A(i,K)+A(k,j)} package com.algothrim;/* * 两个结点之间的最短路径 */public class DynamicPlan { public static void findS

图的最短路径-----------Dijkstra算法详解(TjuOj2870_The Kth City)

做OJ需要用到搜索最短路径的题,于是整理了一下关于图的搜索算法: 图的搜索大致有三种比较常用的算法: 迪杰斯特拉算法(Dijkstra算法) 弗洛伊德算法(Floyd算法) SPFA算法 Dijkstra算法使用了广度优先搜索解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树. 算法的思路: Dijkstra算法采用的是一种贪心的策略,声明一个数组dis来保存源点到各个顶点的最短距离和一个保存已经找到了最短路径的顶点的集合:T,初始时,原点 s 的路径权重被赋为 0 (dis