本文主要是将我对于我对于迪杰斯特拉算法的理解写出来,同时通过例题来希望能够加深对于算法的理解,其中有错误的地方希望大家指正。

迪杰斯特拉算法

我将这个算法理解成一个局部到整体的算法,这个方法确实越研究就会发现越经典。

首先可以将整个图的节点看成两个集合:一个是S,一个是U-S.如果是求v0到图中各点的最短距离的话,那么S就是已经确认到v0距离最短的点,U-S则是对于整体的点集合U,还没有加入S集合的点.

这里提出一个算法总体的思想,将所有的点按照一定的原则加入到S集就是解集。而这个解法就是重点了:如果我们能通过图邻接矩阵或者已经已知了图中点与点直连的距离,那么我们可以确定S集合的点就是到v0的最短路径(注意这个路径不是两点之间的距离而是图中可联通的任意两点的距离)。

好了问题缩小为求到v0路径最短的点,但是还需要注意的是:如果图中一点v加入到S集合中,图中其他点由于联通性就可能会减小到v0的最短路径。

如果不太清楚就依照图然后比对,最后再对照算法整理一下思路,如下是示例图(参考):

                 

算法步骤:

a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。

b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。

c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。

d.重复步骤b和c直到所有顶点都包含在S中。

根据以上的思想整理一下,可以包括两部分:

1.找到一个未加入到S集合的节点同时到v0的距离还是最小的节点u,将其加入到S集合中。

2.通过v0节点来更新该点到v0的距离.比如没有加入集合S的点v,如果v到v0的距离大于v到u和v0到u的最短距离就将v到v0的距离更新为新的最短距离。

具体的算法示例为(实例仅是为了说明思想,所以请结合实际情况修改使用):

 1 #include<iostream>
 2 using namespace std;
 3
 4
 5 int edgs[100][100];     //边
 6 int dist[MAXNUM];        //v0到各边的值
 7 int prev[MAXNUM];       //前驱数组
 8
 9 void Dijkstra(int v0,int n)
10 {
11     bool S[MAXNUM];        //确定顶点是否在S集合中
12
13      for(int i=0;i<n;i++)
14      {
15          dist[i]=edgs[v0][i];    //vo到个点的初值
16          S[i]=false;         //所有节点未加入S
17          if(dist[i] ==MAXINT)
18          {
19              prev[i]=-1;     //没有前驱节点
20          }
21          else
22              prev[i]=v0;
23      }
24
25      dist[v0] =0;
26      S[v0]=true;
27      /*
28      求v到v0的最短距离,将v加到S集中
29      */
30      for(int i=1;i<n;i++)
31      {
32          int min    =MAXINT;
33          int u=v0;
34
35          //找到当前未使用点的DISJ[i]最小值
36          for(int j=0;j<n;j++)
37          {
38              if((!S[j]) && dist[j]<min)
39              {
40                  u=j;
41                  min=dist[j];
42              }
43
44             S[u]=true;   //找到最短路径  加入顶点
45
46              //以新加入的节点    更新从 v0触发到集合V-S的顶点路径长度
47              for(int j=0;j<n;j++)
48                  if((!S[j]) && dist[u]+edgs[u][j]<dist[j])    //通过新加入节点找到更短路径
49                  {
50                      dist[j]=dist[u]+edgs[u][j];
51                      prev[j]=u;     //更新前驱节点
52                  }
53          }
54      }
55 }
56 int main()
57 {
58     int n;     //图的顶点数
59     cin>>n;
60      for(int i=0;i<n;i++)
61          for(int j=0;j<n;j++)
62              cin>>edgs[i][j];     //边的权值
63
64
65     return 0;
66 } 

  好了这是我见到的最传统的写法(书上基本都这么写),我上面提到了算法实现其实分为两部分,聪明的你可否想到:能否调换两个部分的顺序:先通过比较路径的大小再来更新S集合中的点,之前我确实没有考虑过类似的问题,但是这次通过看了一些代码和思索发现这样是可以的而且不失为一种好的方法。下面通过一道算法题(选自https://www.patest.cn/contests/pat-a-practise/1003)来将两种思想通过代码的方式列举一下。

1003. Emergency (25)

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input

Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (<= 500) - the number of cities (and the cities are numbered from 0 to N-1), M - the number of roads, C1 and C2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c1, c2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C1 to C2.

Output

For each test case, print in one line two numbers: the number of different shortest paths between C1 and C2, and the maximum amount of rescue teams you can possibly gather.
All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input

5 6 0 2

1 2 1 5 3

0 1 1

0 2 2

0 3 1

1 2 1

2 4 1

3 4 1

Sample Output

2 4

对照本题,其实可以根据题意可以很快的转化到以图为模型的点与点之间的求解。对于我来说基本就确定用迪杰斯特拉算法来AC.将本体的元素抽象一下可以把每一个城市看成一个点,同时城市与城市之间的路可以看成边,边有对应的权值大小。有一些细节上的改动,比如:需要我们确定最短边的个数以及相应的一些点的权值的计算。好我们同样依照上面的算法来解决。下面是我的算法(已经通过测试),主要上面提到的两个主要部分:

  1 /*
  2 author :LY   2016.5.31
  3 */
  4 #include<iostream>
  5 using namespace std;
  6 #define INF 9999999
  7
  8 int N;     //number of city
  9 int M;     //number of road
 10 int start,en;
 11 const int MAXNUM=500;     //最大的顶点数
 12
 13 int city[MAXNUM];
 14 int path[MAXNUM][MAXNUM];    //边
 15 int dist[MAXNUM];        //v0到各边的最小值
 16 int pathcount[MAXNUM];    //最短边的数量
 17 int amount[MAXNUM];      //可获取的最大资源数
 18 bool S[MAXNUM];       //确定顶点是否在S集合中
 19
 20 void Dijs(int v0)     //根据dij来确定两点之间最短
 21 {
 22          //将v0加入S
 23     dist[v0]=0;
 24     S[v0]=true;
 25     amount[v0]=city[v0];
 26      int u=v0;
 27
 28     for(int i=0;i<N;i++)
 29     {
 30         dist[i]=path[v0][i];    //optial
 31         if(dist[i]!=INF && i!=v0)
 32         amount[i]=amount[v0]+city[i];
 33
 34        }
 35
 36
 37     /*
 38      求v到v0的最短距离,将v加到S集中
 39      */
 40     for(int i=1;i<N;i++)
 41     {
 42
 43               //求出v0到v的最短路径,将此点加入到S中
 44          int min=INF;
 45
 46          for(int j=0;j<N;j++)  //找到最小值
 47          {
 48              if(!S[j]&&dist[j]<min)
 49              {
 50                  u=j;
 51                  min=dist[j];
 52              }
 53          }
 54
 55          S[u]=true;    //将v点加入S
 56
 57         //更新v0到各点的路径长度
 58          for(int j=0 ;j<N; j++)
 59          {
 60              if(!S[j]&&dist[j]>dist[u]+path[u][j])
 61              {
 62                  dist[j]= dist[u]+path[u][j];   //    更新路径
 63                 amount[j]=amount[u]+city[j];
 64                 pathcount[j]=pathcount[u];
 65              }
 66              else if(!S[j]&&dist[j]==dist[u]+path[u][j])
 67              {
 68                  pathcount[j]+=pathcount[u];
 69
 70                  if(amount[j]<city[j]+amount[u])
 71                  {
 72                      amount[j]=city[j]+amount[u];
 73                  }
 74              }
 75          }
 76
 77     }
 78 }
 79 int main()
 80 {
 81
 82     scanf("%d",&N);
 83     scanf("%d",&M);
 84     scanf("%d",&start);
 85     scanf("%d",&en);
 86
 87     for(int i=0;i<N;i++)
 88     {
 89         scanf("%d",&city[i]);
 90     }
 91
 92     int i=0,j=0;
 93     //初始化dij数组
 94     for(i=0;i<N;i++)
 95     {
 96         dist[i]=INF;
 97         pathcount[i]=1;
 98         S[i]=false;
 99         amount[i]=city[i];
100         for(j=0;j<N;j++)
101         {
102             path[i][j]=INF;
103         }
104     }
105
106     int k1=0,k2=0,k3=0;
107     for(int j=0;j<M;j++)
108     {
109         scanf("%d",&k1);
110         scanf("%d",&k2);
111         scanf("%d",&k3);
112         path[k1][k2]=k3;     //the  length  of road between C1 and C2
113         path[k2][k1]=k3;
114     }
115     Dijs(start);
116
117     printf("%d %d\n",pathcount[en],amount[en]);
118     return 0;
119 } 

  我提到了可以调换顺序来实现,首先通过先比较的路径,再将点加入到S集合中,不过思路需要很清晰,以下是代码,对照一下可以加深对于程序的理解:

 1 #include<iostream>
 2 #include <cstdio>
 3 #define MAX 500
 4 #define INF 999999999
 5 int dist[MAX];
 6 bool mark[MAX];
 7 int mp[MAX][MAX];
 8 int teams[MAX];
 9 int amount[MAX];
10 int pathcount[MAX];
11 int n, m, start, en;
12
13 void dijkstra(int s){
14     dist[s] = 0;
15     amount[s] = teams[s];
16     mark[s] = true;
17     int newP = s;
18     while (newP != en){
19         for (int i = 0; i < n; i++){
20             if (mark[i] == false){
21                 if (dist[i] > dist[newP] + mp[newP][i]){
22                     dist[i] = dist[newP] + mp[newP][i];
23                     amount[i] = amount[newP] + teams[i];
24                     pathcount[i] = pathcount[newP];
25                 }
26                 else if (dist[i] == dist[newP] + mp[newP][i]){
27                     pathcount[i] += pathcount[newP];
28                     if (amount[i] < amount[newP] + teams[i])
29                         amount[i] = amount[newP] + teams[i];
30                 }
31             }
32         }
33         int dmin = INF;
34         for (int i = 0; i < n; i++){
35             if (mark[i] == false && dist[i] < dmin){
36                 dmin = dist[i];
37                 newP = i;
38             }
39         }
40         mark[newP] = true;
41     }
42 }
43
44 int main(){
45     scanf("%d%d%d%d", &n, &m, &start, &en);
46     for (int i = 0; i < n; i++){
47         scanf("%d", &teams[i]);
48     }
49     for (int i = 0; i < n; i++){
50         dist[i] = INF;
51         pathcount[i] = 1;
52         mark[i] = false;
53         for (int j = 0; j < n; j++)
54             mp[i][j] = INF;
55     }
56     for (int i = 0; i < m; i++){
57         int c1, c2, L;
58         scanf("%d%d%d", &c1, &c2, &L);
59         mp[c1][c2] = mp[c2][c1] = L;
60     }
61     dijkstra(start);
62     printf("%d %d\n", pathcount[en], amount[en]);
63     return 0;
64 }

由于本人水平有限,参考了一些大神的博文:

http://blog.csdn.net/xtzmm1215/article/details/39006079

http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html

  希望大家批评指正!

  日进一小步,月过一大步~~加油!!!

转载于:https://www.cnblogs.com/ly199553/p/5547808.html

迪杰斯特拉算法——PAT 1003相关推荐

  1. 迪杰斯特拉算法(C语言实现)

    迪杰斯特拉算法(C语言实现) 如上图,求以a为源点到个顶点的最短路劲. #include "stdio.h" #include "stdlib.h" //用一个 ...

  2. C++迪杰斯特拉算法求最短路径

    一:算法历史 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是以 ...

  3. 单源最短路径-Dijkstra(迪杰斯特拉算法)

    迪杰斯特拉算法时间复杂度为O(n^2),其中n为顶点个数. 该算法用于求单源最短路径.并且图中的边不允许带负权值. #include <iostream> using namespace ...

  4. JavaScript实现dijkstra迪杰斯特拉算法(附完整源码)

    JavaScript实现dijkstra迪杰斯特拉算法 PriorityQueue完整源代码 MinHeap.js完整源代码 Heap.js完整源代码 Comparator.js完整源代码 dijks ...

  5. C++实现Dijkstra(迪杰斯特拉)算法(附完整源码)

    C++Dijkstra迪杰斯特拉算法的实现 C++Dijkstra(迪杰斯特拉)算法的完整源码(定义,实现,main函数测试) C++Dijkstra(迪杰斯特拉)算法的完整源码(定义,实现,main ...

  6. C语言实现Dijkstra(迪杰斯特拉)算法(附完整源码)

    Dijkstra迪杰斯特拉 Graph结构体定义 迪杰斯特拉算法完整源码(定义,实现,main函数测试) Graph结构体定义 struct Graph {int vertexNum;int **ed ...

  7. 狄斯奎诺算法 c语言,图的邻接表实现迪杰斯特拉算法(C语言).doc

    图的邻接表实现迪杰斯特拉算法(C语言) /*迪杰斯特拉算法(狄斯奎诺算法)解决的是从源点到其它所有顶点的最短路径问题*/ //算法实现: #include #include #define MAX 2 ...

  8. java迪杰斯特拉算法介绍_178-迪杰斯特拉(Dijkstra)算法基本介绍

    2.网上数据结构和算法的课程不少,但存在两个问题: 1)授课方式单一,大多是照着代码念一遍,数据结构和算法本身就比较难理解,对基础好的学员来说,还好一点,对基础不好的学生来说,基本上就是听天书了 2) ...

  9. 【数据结构】图的应用(普利姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法、拓扑排序)

    最小生成树 什么是最小生成树 是一棵树 - 无回路 - |V|个顶点一定有|V|-1条边 是生成树 - 包含全部顶点 - |V|-1条边全在图里 贪心算法 什么是"贪":每一步都要 ...

最新文章

  1. svn: Checksum mismatch while updating 'D:\workspace\demo\test\.svn\text-base\test.php.svn-base'
  2. .Net新手☞数据库操作
  3. 求n!的算法和C 实现
  4. php7版本搭建sqli labs,CentOS 7 LAMP搭建并且部署sqli-labs
  5. [转载]强大的grep用法详解:grep与正则表达式
  6. 面试官:什么是对象池?有什么用?别说你还不会!
  7. Eclipse安装包 百度网盘
  8. Win10 卸载了某软件,右键还有该软件,如何删除呢?
  9. Java基础教程——字符流
  10. 三角函数π/2转化_分析最简单的正弦和余弦三角函数的图像
  11. python中exp函数_python的math函数 python中虚数函数exp怎么表示
  12. BTC EmbeddedPlatform安装手记
  13. 6-9 字符串匹配 - C/C++ 数组及字符串c语言c++
  14. FFMpeg.AutoGen(1)讲解官方example代码:Main函数、 解码
  15. 人脸识别60年:欧盟通用数据保护条例真的算“史上最严”吗
  16. web测试-sql注入漏洞
  17. bzoj1933: [Shoi2007]Bookcase 书柜的尺寸
  18. C/C++基本数据类型大小
  19. Excel暗藏的赛车游戏(转)
  20. 阿里外贸国际站全屏视频代码视频怎么装修教程

热门文章

  1. 中国电子信息工程科技发展十大趋势(2019)发布
  2. 两种超级智能,哪一个对人类未来影响更为深远?
  3. 人与动物之间有没有一条不可逾越的鸿沟?——从基础存在论到生命哲学
  4. 王飞跃:平行汽车到平行驾驶,从“功能汽车”到“智能汽车”
  5. 美科学基金会欲向公众征集想法
  6. DeepMind新论文:给侧面照片,AI给你脑补出正面
  7. 外界对程序员的误解究竟有多深?
  8. Sudo 漏洞隐患不断,macOS 也受牵连!
  9. HarmonyOS 手机应用开发者 Beta 版到来,对开发者意味着什么
  10. java线程同步以及对象锁和类锁解析(多线程synchronized关键字)