The shortest path problem---detailed explanation of Dijkstra's algorithm

https://blog.csdn.net/qq_35644234/article/details/60870719

1. Introduction to the shortest path problem

Explanation of the problem: 
The weight of the edge and the smallest path from a vertex in the graph to another vertex is called the shortest path

Algorithm to solve the problem:

In this blog, we will give a detailed introduction to the Dijkstra algorithm.

2. Introduction to Dijkstra's algorithm

  • Algorithm Features:

    Dijkstra's algorithm uses breadth-first search to solve the single-source shortest path problem of a weighted directed or undirected graph, and the algorithm finally obtains a shortest path tree. This algorithm is often used in routing algorithms or as a submodule of other graph algorithms.

  • algorithm idea

    Dijkstra's algorithm adopts a greedy strategy, declaring an array dis to save the shortest distance from the source point to each vertex and a collection of vertices that have found the shortest path: T, initially, the path weight of the origin s is assigned is 0 (dis[s] = 0). If there is a directly reachable edge (s, m) for vertex s, set dis[m] to w(s, m), and set the path length of all other (s unreachable) vertices to infinity. Initially, the set T has only vertex s. 
    Then, select the minimum value from the dis array, then the value is the shortest path from the source point s to the vertex corresponding to this value, and add this point to T, OK, then a vertex is completed, 
    and then we need to look at the new Whether the added vertices can reach other vertices and see if the path length through this vertex to other points is shorter than the source point directly, if so, then replace the value of these vertices in dis. 
    Then, find the minimum value from dis, and repeat the above actions until T contains all the vertices of the graph.

3. Demonstration of Dijkstra's algorithm example

Below I find the shortest path from vertex v1 to each other vertex in the following graph

write picture description here

The first step, we first declare a dis array, the initialized value of the array is: 
write picture description here

The initialization of our vertex set T is: T={v1}

Since it is to find the shortest distance from the v1 vertex to the other vertices, first find a vertex closest to the 1st vertex. Through the array dis, it can be known that the current closest to the v1 vertex is the v3 vertex. When vertex No. 2 is selected, the value of dis[2] (the subscript starts from 0) has changed from "estimated value" to "determined value", that is, the shortest distance from the v1 vertex to the v3 vertex is the current dis[2] value. Add V3 to T. 
why? Because the v3 vertex is currently the closest to the v1 vertex, and all the edges of this graph are positive numbers, it is definitely impossible to transit through the third vertex, which further shortens the distance from the v1 vertex to the v3 vertex. Because the distance from v1 to other vertices is definitely not as short as v1 to v3 vertices.

OK, since the shortest path of a vertex has been determined, we will now have an out-degree according to the newly entered vertex V3, and find that the arc tails with v3 are: < v3, v4 >, then let's look at the path: v1–v3 Whether the length of –v4 is shorter than v1-v4 is actually obvious, because dis[3] represents that the length of v1-v4 is infinite, and the length of v1-v3-v4 is: 10+50= 60, so update the value of dis[3] and get the following result: 
write picture description here

So dis[3] needs to be updated to 60. This process has a technical term called "relaxation". That is, the distance from the v1 vertex to the v4 vertex is dis[3], and the relaxation is successful through the <v3,v4> edge. This is the main idea of ​​Dijkstra's algorithm: relax the path from the v1 vertex to the other vertices by "edges".

Then, we look for the minimum value from other values ​​except dis[2] and dis[0], and find that the value of dis[4] is the smallest. Through the principle explained before, we can know that the shortest distance from v1 to v5 is dis The value of [4], then, we add v5 to the set T, and then, consider whether the out-degree of v5 will affect the value of our array dis, v5 has two out-degrees: < v5, v4> and < v5, v6>, then we find: the length of v1–v5–v4 is: 50, and the value of dis[3] is 60, so we have to update the value of dis[3]. In addition, the length of v1-v5-v6 is: 90, and dis[5] is 100, so we need to update the value of dis[5]. The updated dis array is as follows: 
write picture description here

Then, continue to select the smallest value from the values ​​of the undetermined vertices in dis, and find that the value of dis[3] is the smallest, so v4 is added to the set T. At this time, the set T={v1,v3, v5, v4}, then, consider whether the out-degree of v4 will affect the value of our array dis, v4 has an out-degree: < v4, v6 >, then we find: the length of v1–v5–v4–v6 is: 60 , and the value of dis[5] is 90, so we need to update the value of dis[5]. The updated dis array is as follows: 
write picture description here

Then, we use the same principle to determine the shortest paths of v6 and v2 respectively, and the final value of the array of dis is as follows: 
write picture description here

Therefore, from the figure, we can find that the value of v1-v2 is: ∞, which means that there is no path from v1 to v2. So the final result we get is:

起点  终点    最短路径    长度
v1    v2     无          ∞    
      v3     {v1,v3}    10
      v4     {v1,v5,v4}  50
      v5     {v1,v5}    30
      v6     {v1,v5,v4,v6} 60
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4. Code implementation of Dijkstra algorithm (c++)

  • Code for Dijkstra.h file
/************************************************************/
/*                程序作者:Willam                          */
/*                程序完成时间:2017/3/8                    */
/*                有任何问题请联系:[email protected]       */
/************************************************************/
//@尽量写出完美的程序

#pragma once
//#pragma once是一个比较常用的C/C++杂注,
//只要在头文件的最开始加入这条杂注,
//就能够保证头文件只被编译一次。

#include<iostream>
#include<string>
using namespace std;

/*
本程序是使用Dijkstra算法实现求解最短路径的问题
采用的邻接矩阵来存储图
*/
//记录起点到每个顶点的最短路径的信息
struct Dis {
    string path;
    int value;
    bool visit;
    Dis() {
        visit = false;
        value = 0;
        path = "";
    }
};

class Graph_DG {
private:
    int vexnum;   //图的顶点个数
    int edge;     //图的边数
    int **arc;   //邻接矩阵
    Dis * dis;   //记录各个顶点最短路径的信息
public:
    //构造函数
    Graph_DG(int vexnum, int edge);
    //析构函数
    ~Graph_DG();
    // 判断我们每次输入的的边的信息是否合法
    //顶点从1开始编号
    bool check_edge_value(int start, int end, int weight);
    //创建图
    void createGraph();
    //打印邻接矩阵
    void print();
    //求最短路径
    void Dijkstra(int begin);
    //打印最短路径
    void print_path(int);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • Code for Dijkstra.cpp file
#include"Dijkstra.h"

//构造函数
Graph_DG::Graph_DG(int vexnum, int edge) {
    //初始化顶点数和边数
    this->vexnum = vexnum;
    this->edge = edge;
    //为邻接矩阵开辟空间和赋初值
    arc = new int*[this->vexnum];
    dis = new Dis[this->vexnum];
    for (int i = 0; i < this->vexnum; i++) {
        arc[i] = new int[this->vexnum];
        for (int k = 0; k < this->vexnum; k++) {
            //邻接矩阵初始化为无穷大
                arc[i][k] = INT_MAX;
        }
    }
}
//析构函数
Graph_DG::~Graph_DG() {
    delete[] dis;
    for (int i = 0; i < this->vexnum; i++) {
        delete this->arc[i];
    }
    delete arc;
}

// 判断我们每次输入的的边的信息是否合法
//顶点从1开始编号
bool Graph_DG::check_edge_value(int start, int end, int weight) {
    if (start<1 || end<1 || start>vexnum || end>vexnum || weight < 0) {
        return false;
    }
    return true;
}

void Graph_DG::createGraph() {
    cout << "请输入每条边的起点和终点(顶点编号从1开始)以及其权重" << endl;
    int start;
    int end;
    int weight;
    int count = 0;
    while (count != this->edge) {
        cin >> start >> end >> weight;
        //首先判断边的信息是否合法
        while (!this->check_edge_value(start, end, weight)) {
            cout << "输入的边的信息不合法,请重新输入" << endl;
            cin >> start >> end >> weight;
        }
        //对邻接矩阵对应上的点赋值
        arc[start - 1][end - 1] = weight;
        //无向图添加上这行代码
        //arc[end - 1][start - 1] = weight;
        ++count;
    }
}

void Graph_DG::print() {
    cout << "图的邻接矩阵为:" << endl;
    int count_row = 0; //打印行的标签
    int count_col = 0; //打印列的标签
    //开始打印
    while (count_row != this->vexnum) {
        count_col = 0;
        while (count_col != this->vexnum) {
            if (arc[count_row][count_col] == INT_MAX)
                cout << "∞" << " ";
            else
            cout << arc[count_row][count_col] << " ";
            ++count_col;
        }
        cout << endl;
        ++count_row;
    }
}
void Graph_DG::Dijkstra(int begin){
    //首先初始化我们的dis数组
    int i;
    for (i = 0; i < this->vexnum; i++) {
        //设置当前的路径
        dis[i].path = "v" + to_string(begin) + "-->v" + to_string(i + 1);
        dis[i].value = arc[begin - 1][i];
    }
    //设置起点的到起点的路径为0
    dis[begin - 1].value = 0;
    dis[begin - 1].visit = true;

    int count = 1;
    //计算剩余的顶点的最短路径(剩余this->vexnum-1个顶点)
    while (count != this->vexnum) {
        //temp用于保存当前dis数组中最小的那个下标
        //min记录的当前的最小值
        int temp=0;
        int min = INT_MAX;
        for (i = 0; i < this->vexnum; i++) {
            if (!dis[i].visit && dis[i].value<min) {
                min = dis[i].value;
                temp = i;
            }
        }
        //cout << temp + 1 << "  "<<min << endl;
        //把temp对应的顶点加入到已经找到的最短路径的集合中
        dis[temp].visit = true;
        ++count;
        for (i = 0; i < this->vexnum; i++) {
            //注意这里的条件arc[temp][i]!=INT_MAX必须加,不然会出现溢出,从而造成程序异常
            if (!dis[i].visit && arc[temp][i]!=INT_MAX && (dis[temp].value + arc[temp][i]) < dis[i].value) {
                //如果新得到的边可以影响其他为访问的顶点,那就就更新它的最短路径和长度
                dis[i].value = dis[temp].value + arc[temp][i];
                dis[i].path = dis[temp].path + "-->v" + to_string(i + 1);
            }
        }
    }

}
void Graph_DG::print_path(int begin) {
    string str;
    str = "v" + to_string(begin);
    cout << "以"<<str<<"为起点的图的最短路径为:" << endl;
    for (int i = 0; i != this->vexnum; i++) {
        if(dis[i].value!=INT_MAX)
        cout << dis[i].path << "=" << dis[i].value << endl;
        else {
            cout << dis[i].path << "是无最短路径的" << endl;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • The code of the main.cpp file
#include"Dijkstra.h"


//检验输入边数和顶点数的值是否有效,可以自己推算为啥:
//顶点数和边数的关系是:((Vexnum*(Vexnum - 1)) / 2) < edge
bool check(int Vexnum, int edge) {
    if (Vexnum <= 0 || edge <= 0 || ((Vexnum*(Vexnum - 1)) / 2) < edge)
        return false;
    return true;
}
int main() {
    int vexnum; int edge;

    cout << "输入图的顶点个数和边的条数:" << endl;
    cin >> vexnum >> edge;
    while (!check(vexnum, edge)) {
        cout << "输入的数值不合法,请重新输入" << endl;
        cin >> vexnum >> edge;
    }
    Graph_DG graph(vexnum, edge);
    graph.createGraph();
    graph.print();
    graph.Dijkstra(1);
    graph.print_path(1);
    system("pause");
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

enter:

6 8
1 3 10
1 5 30
1 6 100
2 3 5
3 4 50
4 6 10
5 6 60

5 4 20

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325641460&siteId=291194637