图论(三) (一)最短路径算法 2.Dijkstra算法

Dijkstra 算法解决的是带权重的有向图上单源最短路径问题,该算法要求所有边的权重都为非负值。该算法的时间复杂度是O(N2),相比于处理无负权的图时,比Bellmad-Ford算法效率更高。

算法描述:

首先引用《算法导论》中的一段比较官方的话,如果可以看懂,那下一部分就可以跳过了:

“Dijkstra算法在运行过程中维持的关键信息是一组结点集合S。从源结点s到该集合中每个结点之间的最短路径已经被找到。算法重复从结点集 V - S 中算则最短路径估计的最小的结点 u ,将 u 加入到集合S,然后对所有从 u 出发的边进行松弛。” 所谓松弛操作,简单的说就是更新两点间的最短距离。

不是很好理解对吧,那么下面的描述是更容易理解的一种描述:

设起始点为s,dis[v]表示s点到v点的最短路径,pre[v]是v的前驱结点,用来输出路径。

1、初始化:dis[v]=∞(v≠s) dis[s]=0,pre[s]=0;

2、for(i=1;i<=n;i++)

(1)在没有被访问过的点中,即上述的V - S集合,找到一个点 u 使得dis[u]是最小的。

(2)标记 u 为已确定的最短路径。

(3)for(每个与 u 相连且没有确定过最短距离的点 v)

if(dis[u]+m[u][v]<dis[v]){

dis[v]=dis[u]+m[u][v];

pre[v]=u;

}

3、结束:结果dis[v]就是s到v的最短距离。

算法理解:

其中自以为有几点理解需要说明:

1、为什么用到中间点?

2、取s到中间点的距离时采用什么策略?

第一个问题,从起点到另一个点的最短路径至少会经历一个中间点,所以我们要求出经过这个中间的到另一个点的路径,就要先求出起点到中间点的最短路径。

第二个问题,其实这里采用的是一中贪心的策略。当然这个策略可以被严格证明是正确的,但是我也一知半解,只知道是可以被证明的,在这里也就不浪费时间了。(详细可以参考《算法导论》)

最后,解释一下为什么有负权边的时候不可以:

连接矩阵如下(图可以自己在旁边画一下):

1 2 3

1 \ 2 1

2 2 \ -4

3 1 -4 \

那么第一次标记的点就为3并且把dis[3]记为1,但实际上dis[3]应该时-2,因此就会出现错误。

最后附上一段不那么标准的代码:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 int m[100][100],e,dist[100],n,b[100],pre[100],dist[100];
 4 void dij(int s){
 5      b[s]=1;
 6      int i,j;
 7      for(i=1;i<=n;i++)
 8       dist[i]=m[s][i];
 9      dist[s]=0;
10      pre[s]=0;
11
12      for(i=1;i<=n;i++){
13       int min=1000000,k=0;
14       for(j=1;j<=n;j++)
15        if(b[j]!=1 && dist[j]<min)
16         {min=dist[j];k=j;}
17        b[k]=1;
18        for(j=1;j<=n;j++)
19         if(min+m[k][j]<dist[j]&&b[j]!=1)
20          {
21           dist[j]=min+m[k][j];
22           pre[j]=i;
23           }
24       }
25       for(i=1;i<=n;i++)
26        if(i!=s)
27         printf("%d ",dist[i]);
28      }
29 int main(){
30     int i,j;
31     scanf("%d%d",&n,&e);
32     memset(b,0,sizeof(b));
33     memset(m,10000,sizeof(m));
34     for(i=1;i<=e;i++){
35      int x,y;
36      scanf("%d%d",&x,&y);
37      scanf("%d",&m[x][y]);
38      }
39     int w;
40     scanf("%d",&w);
41     dij(w);
42     system("pause");
43     return 0;
44     }

原文地址:https://www.cnblogs.com/uncklesam7/p/8831204.html

时间: 2024-10-09 03:26:30

图论(三) (一)最短路径算法 2.Dijkstra算法的相关文章

图论(四)------非负权有向图的单源最短路径问题,Dijkstra算法

Dijkstra算法解决了有向图G=(V,E)上带权的单源最短路径问题,但要求所有边的权值非负. Dijkstra算法是贪婪算法的一个很好的例子.设置一顶点集合S,从源点s到集合中的顶点的最终最短路径的权值均已确定.算法反复选择具有最短路径估计的顶点u,并将u加入到S中,对u 的所有出边进行松弛.如果可以经过u来改进到顶点v的最短路径的话,就对顶点v的估计值进行更新. 如上图,u为源点,顶点全加入到优先队列中. ,队列中最小值为u(值为0),u出队列,对u的出边进行松弛(x.v.w),队列最小值

最短路径问题的Dijkstra算法

问题 是由荷兰计算机科学家艾兹赫尔·戴克斯特拉提出.迪科斯彻算法使用了广度优先搜索解决非负权有向图的单源最短路径问题,算法最终得到一个最短路径树>    .该算法常用于路由算法或者作为其他图算法的一个子模块. 这个算法的python实现途径很多,网上能够发现不少.这里推荐一个我在网上看到的,本来打算自己写,看了这个,决定自己不写了,因为他的已经太好了. 以下代码来自网络,但是我不能写来源,因为写了来源网址,这里就不让我发出这篇文章.这不是逼着我剽窃吗? 解决(Python) #!/usr/bin

最短路径算法(Dijkstra算法、Floyd-Warshall算法)

最短路径算法具体的形式包括: 确定起点的最短路径问题:即已知起始结点,求最短路径的问题.适合使用Dijkstra算法. 确定终点的最短路径问题:即已知终结结点,求最短路径的问题.在无向图中,该问题与确定起点的问题完全等同:在有向图中,该问题等同于把所有路径方向反转的确定起点的问题. 确定起点终点的最短路径问题:即已知起点和终点,求两结点之间的最短路径. 全局最短路径问题:求图中所有的最短路径.Floyd-Warshall算法. dijkstra算法思想: 开始时,S={u},T=V-{u}; 对

【数据结构】拓扑排序、最短路径算法、Dijkstra算法、无环图等等

图的定义 图(graph)G = (V,E)由顶点(vertex)的集V和边(Edge)的集E组成.有时也把边称作弧(arc),如果点对(v,w)是有序的,那么图就叫做有向的图(有向图).顶点v和w邻接(adjacent)当且仅当(v,w)属于E. 如果无向图中从每一个顶点到其他每个顶点都存在一条路径,则称该无向图是连通的(connected).具有这样性质的有向图称为是强连通的(strongly connected).如果有向图不是强连通的,但它的基础图(underlying graph)(也

数据结构与算法系列研究七——图、prim算法、dijkstra算法

图.prim算法.dijkstra算法 1. 图的定义 图(Graph)可以简单表示为G=<V, E>,其中V称为顶点(vertex)集合,E称为边(edge)集合.图论中的图(graph)表示的是顶点之间的邻接关系. (1) 无向图(undirect graph)      E中的每条边不带方向,称为无向图.(2) 有向图(direct graph)      E中的每条边具有方向,称为有向图.(3) 混合图       E中的一些边不带方向, 另一些边带有方向.(4) 图的阶      指

最小生成树算法之 Dijkstra算法

Dijkstra算法 Dijkstra算法是典型最短路算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低. Dijkstra算法是用来求任意两个顶点之间的最短路径.在该算法中,我们用邻接矩阵来存储图.在该程序中设置一个二维数组来存储任意两个顶点之间的边的权值.可以将任意一个图的信息通过键盘输入,让后在输入要查找的两个顶点,程序可以自动求出这两个顶点之间的最短路

图论(三) (一)最短路径问题 Bellman-Ford算法

简要:Bellman-Ford算法计算的仍然是从一个点到其他所有点的最短路径算法,其时间复杂度是O(NE),N表示点数,E表示边数,不难看出,当一个图稍微稠密一点,边的数量会超过点数那么实际上效率是低于Dijkstra算法的.但是本算法可以计算存在负权边的情况(不存在负回路),因此可以用于更广泛的情况,但其实在日常解题应用中我们基本不会用到该算法,因为有一个比它效率更高的算法即SPFA算法,下一章会介绍到.SPFA算法其实是从Bellman-Ford算法演变而来的,那么从基础的开始,我们先来理解

最短路径算法之Dijkstra算法(java实现)

前言 Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法.该算法被称为是“贪心算法”的成功典范.本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码. 一.知识准备: 1.表示图的数据结构 用于存储图的数据结构有多种,本算法中笔者使用的是邻接矩阵.  图的邻接矩阵存储方式是用两个数组来表示图.一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息. 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 从上面可以看出,无向图的边

算法导论--单源最短路径问题(Dijkstra算法)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51918844 单源最短路径是指:给定源顶点s∈V到分别到其他顶点v∈V?{s}的最短路径的问题. Dijkstra算法采用贪心策略:按路径长度递增的顺序,逐个产生各顶点的最短路径.算法过程中需要维护一个顶点集S,此顶点集保存已经找到最短路径的顶点.还需要维护一个距离数组dist, dist[i]表示第i个顶点与源结点s的距离长度. Dijkstra算法思路: S