最短路问题迪杰斯特拉算法
- 格式:ppt
- 大小:337.00 KB
- 文档页数:19
最短路问题(short-path problem)若网络中的每条边都有一个权值值(长度、成本、时间等),则找出两节点(通常是源节点与结束点)之间总权和最小的路径就是最短路问题。
最短路问题是网络理论解决的典型问题之一,可用来解决管路铺设、线路安装、厂区布局和设备更新等实际问题。
最短路问题,我们通常归属为三类:单源最短路径问题(确定起点或确定终点的最短路径问题)、确定起点终点的最短路径问题(两节点之间的最短路径)1、Dijkstra算法:用邻接矩阵a表示带权有向图,d为从v0出发到图上其余各顶点可能达到的最短路径长度值,以v0为起点做一次dijkstra,便可以求出从结点v0到其他结点的最短路径长度代码:procedure dijkstra(v0:longint);//v0为起点做一次dijkstrabegin//a数组是邻接矩阵,a[i,j]表示i到j的距离,无边就为maxlongintfor i:=1 to n do d[i]:=a[v0,i];//初始化d数组(用于记录从v0到结点i的最短路径), fillchar(visit,sizeof(visit),false);//每个结点都未被连接到路径里visit[v0]:=true;//已经连接v0结点for i:=1 to n-1 do//剩下n-1个节点未加入路径里;beginmin:=maxlongint;//初始化minfor j:=1 to n do//找从v0开始到目前为止,哪个结点作为下一个连接起点(*可优化) if (not visit[j]) and (min>d[j]) then//结点k要未被连接进去且最小begin min:=d[j];k:=j;end;visit[k]:=true;//连接进去for j:=1 to n do//刷新数组d,通过k来更新到达未连接进去的节点最小值,if (not visit[j]) and (d[j]>d[k]+a[k,j]) then d[j]:=a[k,j]+d[k];end;writeln(d[n]);//结点v0到结点n的最短路。
最短路问题的求解方法最短路问题是图论中的经典问题之一,它在实际生活中有着广泛的应用,比如在交通规划、通信网络、物流配送等领域都有着重要的作用。
在解决最短路问题时,我们需要找到图中两个顶点之间的最短路径,即使得路径上的边的权值之和最小。
针对不同的图,我们可以采用不同的方法来求解最短路问题,下面将介绍几种常见的求解方法。
首先,最简单直接的方法是暴力搜索法。
暴力搜索法适用于小规模的图,它通过穷举所有可能的路径来找到最短路径。
虽然这种方法在理论上是可行的,但是在实际应用中由于时间复杂度过高,通常不适用于大规模的图。
其次,我们可以使用迪杰斯特拉算法来解决最短路问题。
迪杰斯特拉算法是一种贪心算法,它通过逐步扩展离源点距离最短的节点来逐步求解最短路径。
迪杰斯特拉算法的时间复杂度为O(V^2),其中V为顶点数,因此适用于稠密图。
另外,我们还可以使用贝尔曼-福特算法来求解最短路问题。
贝尔曼-福特算法是一种动态规划算法,它通过多次松弛操作来逐步逼近最短路径。
贝尔曼-福特算法适用于存在负权边的图,但是由于其时间复杂度为O(VE),因此在稠密图中效率较低。
最后,我们还可以使用Floyd-Warshall算法来解决最短路问题。
Floyd-Warshall算法是一种动态规划算法,它通过逐步考察所有顶点对之间的路径来求解最短路径。
Floyd-Warshall算法的时间复杂度为O(V^3),因此适用于小规模图。
总的来说,不同的最短路求解方法适用于不同的图,我们需要根据具体的情况来选择合适的方法。
在实际应用中,我们还可以结合启发式算法、并行算法等方法来进一步提高求解效率。
希望本文介绍的内容能够对读者有所帮助,谢谢!。
dijkstra 最短路优化算法
Dijkstra最短路优化算法是一种用于解决单源最短路径问题的
算法,它采用贪心的思想逐步找到从起点到所有其他节点的最短路径。
算法步骤如下:
1. 初始化距离数组dist[],用于记录从起点到每个顶点的最短
距离。
将起点距离设为0,其他顶点的距离设为无穷大。
2. 创建一个优先队列(最小堆)Q,用于存储待选的顶点。
将
起点加入到Q中。
3. 当Q非空时,重复以下步骤:
- 从Q中取出当前距离最小的顶点u。
- 遍历u的所有邻居节点v,并计算起点到v的距离new_dist。
如果new_dist小于dist[v],则更新dist[v]。
- 将v加入到Q中。
4. 重复步骤3,直到Q为空。
该算法的优化主要包括:
1. 使用最小堆可以快速获取当前距离最小的顶点。
2. 使用一个visited数组记录已经访问过的顶点,避免重复计算。
3. 使用优先队列存储待选的顶点,可以按照距离大小自动排序,减少不必要的遍历。
Dijkstra算法的时间复杂度为O((V+E)logV),其中V是顶点数,E是边数。
最短路dijkstra算法详解最短路问题是图论中的一个经典问题,其目标是在给定图中找到从一个起点到其他所有节点的最短路径。
Dijkstra算法是解决最短路问题的一种常用算法,本文将详细介绍Dijkstra算法的原理、实现以及时间复杂度等相关内容。
一、Dijkstra算法的原理Dijkstra算法是一种贪心算法,其基本思想是从起点开始,逐步扩展到其他节点。
具体而言,Dijkstra算法通过维护一个集合S来记录已经找到了最短路径的节点,以及一个数组dist来记录每个节点到起点的距离。
初始时,S集合为空,dist数组中除了起点外所有节点都被初始化为无穷大。
接下来,重复以下步骤直到所有节点都被加入S集合:1. 从dist数组中选择距离起点最近的未加入S集合的节点u;2. 将u加入S集合;3. 更新与u相邻的未加入S集合的节点v的距离:如果从起点出发经过u可以得到更短的路径,则更新v对应位置上dist数组中存储的值。
重复以上步骤直至所有节点都被加入S集合,并且dist数组中存储了每个节点到起点的最短距离。
最后,根据dist数组中存储的信息可以得到起点到任意节点的最短路径。
二、Dijkstra算法的实现在实现Dijkstra算法时,需要使用一个优先队列来维护未加入S集合的节点,并且每次从队列中选择距离起点最近的节点。
由于C++标准库中没有提供优先队列,因此需要手动实现或者使用第三方库。
以下是一个基于STL堆实现的Dijkstra算法代码示例:```c++#include <iostream>#include <vector>#include <queue>using namespace std;const int INF = 0x3f3f3f3f;vector<pair<int, int>> adj[10001];int dist[10001];void dijkstra(int start) {priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;pq.push(make_pair(0, start));dist[start] = 0;while (!pq.empty()) {int u = pq.top().second;pq.pop();for (auto v : adj[u]) {if (dist[u] + v.second < dist[v.first]) {dist[v.first] = dist[u] + v.second;pq.push(make_pair(dist[v.first], v.first));}}}}int main() {int n, m, start;cin >> n >> m >> start;for (int i = 1; i <= n; i++) {dist[i] = INF;}for (int i = 1; i <= m; i++) {int u, v, w;cin >> u >> v >> w;adj[u].push_back(make_pair(v, w));}dijkstra(start);for (int i = 1; i <= n; i++) {if (dist[i] == INF) {cout << "INF" << endl;} else {cout << dist[i] << endl;}}return 0;}```以上代码中,adj数组用于存储图的邻接表,dist数组用于存储每个节点到起点的最短距离。
最短路问题的三种算法模板最短路算法&模板最短路问题是图论的基础问题。
本篇随笔就图论中最短路问题进⾏剖析,讲解常⽤的三种最短路算法:Floyd算法、Dijkstra算法及SPFA算法,并给出三种算法的模板。
流畅阅读本篇博客需要有图论的基础知识,了解什么是图,什么是最短路,以及⼀些基本语法知识和算法基础。
1、Floyd算法我个⼈认为,Floyd算法是三种最短路算法中最简单、最好理解的算法。
它的适⽤范围是任意两点之间的最短路。
这⼀点是其他两种算法(单源最短路)⽆法⽐拟的。
它的实现思路也很简单:⽤三重循环,枚举断点、起始点和终点(注意:顺序千万不能反!!),如果起始点到断点,断点到终点的距离和⼩于起始点到终点当前状态下的最短路(也就是说找到了⼀个⽐它还短的),那么就更新最短路。
它的优点就是简洁明了,易于理解,但是缺点也显⽽易见,通过它的实现途径,我们可以发现,使⽤Floyd算法的题⼀定要⽤邻接矩阵存图,这样的⼀个⼆维数组显然对空间有着要求,⼀般来讲,只能⽀持不超过500个点的图,假如更多,便⽆法⽀持。
同时,Floyd算法还对时间有着要求,因为是三重循环,所以它的时间复杂度是O(n3)的,这样的复杂度如果出现在⼀个复杂程序中,极其容易TLE,所以,请⼤家使⽤的时候,⼀定要读题读题,慎重慎重!模板:void Floyd(){memset(map,0x3f,sizeof(map));for(int i=1;i<=n;i++)map[i][i]=0;for(int k=1;k<=n;k++)//顺序不要反for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)map[i][j]=min(map[i][k]+map[k][j],map[i][j]);}2、Dijkstra算法Dijkstra算法,中⽂名是迪杰斯特拉算法,简写是DIJ算法。
DIJ算法是求解单源最短路,即从某⼀个源点到达其他所有点的最短路的⼀个经典算法。
最短路的算法--Dijkstra算法在图G中,给定s和t两个顶点。
从s到t可以有多条路径,从这多条路中找出长度最的最短路。
设每条弧的长度均为非负值。
小的路,这样的路称为从s到t的最短路。
设每条弧的长度均为非负值。
下面的算法是由狄杰斯特拉(Dijkstra,1959)提出的,其想法是:设已知图中最接近于顶点s的m个顶点以及从顶点s到这些顶点中每一个顶点的最短路(从s到其本身的最短路是零路,即没有弧的路,其长度为0)。
对顶点s和这m个顶点着色。
然后,最接近于s的个顶点可如下求之:第m+1个顶点可如下求之:对于每一个未着色的顶点y,考虑所有已着色顶点x,把弧(x,y)接在从s到x的最短路后面,这样就得到从s到y的m条不同路。
从这m条路中选出最短的路,它就是从s 到y的最短路。
相应的y点就是最接近于s的第m+1个顶点。
因为所有弧的长度都是非负值,所以从s到最接近于s的第m+1个顶点的最短路必然只使用已着色的顶点作为中间顶点。
的最短路为止。
从m=0开始,将这个过程重复进行下去,直至求得从s到t的最短路为止。
算法:狄杰斯特拉最短路算法第1步开始,所有弧和顶点都未着色。
对每个顶点x指定一个数d(x),d(x)表示从s到x 的最短路的长度(中间顶点均已着色)。
开始时,令d(s)=0,d(x)=∞(对所有x≠s)。
y表示已着色的最后一个顶点。
对始点s着色,令y=s。
如下:第2步对于每个未着色顶点x,重新定义d(x)如下:d(x)=min{ d(x),d(y)+a(y,x)} 公式对于所有未着色顶点x,如d(x)=∞,则算法终止。
因为此时从s到任一未着色的顶点都没有路。
否则,对具有d(x)最小值的未着色顶点x进行着色。
同时把弧(y,x)着色(指向顶点x的弧只有一条被着色)。
令y=x。
第3步如果顶点t已着色,则算法终止。
这时已找到一条从s到t的最短路。
如果t未着色,则转第2步。
步。
注意:已着色的弧不能构成一个圈,而是构成一个根在s的树形图,此树形图称为最短路树形图。
摘要:主要介绍最短路的两种算法,迪杰斯特拉(Dijkstra)以及算法在实际问题中的应用。
关键字:图论,最短路径,树,生成树,迪杰斯特拉(Dijkstra),弗罗伊德(Floyd)算法1 引言最短路问题是图论理论的一个经典问题。
寻找最短路径就是在指定网络中两结点间找一条距离最小的路。
最短路不仅仅指一般地理意义上的距离最短,还可以引申到其它的度量,如时间、费用、线路容量等。
最短路径算法的选择与实现是通道路线设计的基础,最短路径算法是计算机科学与地理信息科学等领域的研究热点,很多网络相关问题均可纳入最短路径问题的范畴之中。
经典的图论与不断发展完善的计算机数据结构及算法的有效结合使得新的最短路径算法不断涌现。
2最短路定义①1若图G=G(V,E)中各边e 都赋有一个实数W(e),称为边e 的权,则称这种图为赋权图,记为G=G(V,E,W)。
定义②2若图G=G(V,E)是赋权图且()0W e ≥,()e E G ∈,若u 是i v 到j v 的路()W u 的权,则称()W u 为u 的长,长最小的i v 到j v 的路()W u 称为最短路。
3、Dijkstra 算法基本步骤③: 令:{}{}_23,1,,,,i n s v i s v v v ===并令:{()()10,j j W v T v v s-==∞∈1、 对j v s -∈,求()(){}()min ,j i ij j T v W v w T v +=。
2、 求(){}min j jv sT v ∈得()kT v ,使()kT v =(){}min j jv sT v ∈令()()k k W v T v =3、若k n v v =则已找到1v 到n v 的最短路距离()k W v ,否则令i k =从s -中删去i v 转1 这样经过有限次迭代则可以求出1v 到n v 的最短路线,可以用一个流程图来表示:第一步 先取()10W v =意即1v 到1v 的距离为0,而()j T v 是对()j T v 所赋的初值。
最短路的dijkstra算法基本过程
最短路的Dijkstra算法基本过程
Dijkstra算法是用来解决最短路径问题的一种算法,它是由荷兰计算机科学家Edsger W. Dijkstra在1959年发明的,是目前最常用的最短路径算法。
它是以贪心策略为基础的,主要是利用局部最优求全局最优。
基本过程如下:
1. 从起点出发,设计出一个距离变量dist[],初始值为无穷大。
2. 将dist[起点]设置为0。
3. 找出当前最近的顶点u,计算出从起点到u的中间点v的最短路径,并更新dist[v]的值,即dist[v] = min(dist[v], dist[u] + w(u,v)),其中w(u,v)表示从u到v的边的权重。
4. 重复步骤3,直到所有的顶点都被处理完为止。
5. 返回dist[],表示从起点到其他所有点的最短路径。
迪杰斯特拉算法(戴克斯特拉算法)(Dijkstra算法)-贪⼼、最短路径问题戴克斯特拉算法:(英语:Dijkstra's algorithm,⼜译迪杰斯特拉算法)由荷兰计算机科学家在1956年提出。
戴克斯特拉算法使⽤了解决赋权的问题。
如图为⼀个有权⽆向图,起始点1到终点5,求最短路径lowcost数组存储下标点到起始点的最短距离,mst数组标记该点是否已标记,如下图,遍历graph数组找出初始点(点1)与个点之间的距离存⼊lowcost(距离<lowcost存⼊),*为⽆穷⼤遍历lowcost数组,找出最⼩值并且没有被标记过(mst != 0),找出的最⼩值的点标记(mst = 0),sum=4遍历graph数组,存⼊lowcost中(注意:8到2的距离+sum<lowcost[8],所以lowcost[8]=graph[2][8]+sum)注意:mst[1]是等于0的,下⾯都是0遍历lowcost数组,找出最⼩值,sum=7以下都依次类推...输⼊:9 14 1 5 1 2 41 8 82 8 32 3 88 9 18 7 63 9 29 7 63 4 73 6 47 6 24 6 144 5 96 5 10输出:24代码:#include <iostream>#include <bits/stdc++.h>using namespace std;#define MAX 100#define MAXCOST 0x7fffffff //int型最⼤值void prim(int graph[][MAX],int n,int start,int end){int lowcost[MAX];int mst[MAX];int sum=0;for(int i=1;i<=n;i++)//将与各点与起始点的距离存⼊lowcost中{lowcost[i]=graph[start][i];mst[i]=1;}mst[start]=0; //起始点被标记for(int i=1;i<=n;i++){if(mst[end]==0)//终点被标记结束{cout<<sum;break;}int min=MAXCOST;int minid=0;for(int j=1;j<=n;j++)//遍历lowcost数组,找最⼩值{if(lowcost[j]<min && mst[j]!=0){min=lowcost[j]; //最⼩值minid=j; //最⼩值下标}}//cout<<"V"<<mst[minid]<<"-V"<<minid<<"="<<min<<endl;sum=min;//cout<<sum<<endl;mst[minid]=0; //最⼩值下标点被标记for(int j=1;j<=n;j++)//找最⼩值点与各点的距离{if(graph[minid][j]==MAXCOST)//如果此点与最⼩值点没有联系(距离为最⼤值)则lowcost不变,跳过{continue;}else if(graph[minid][j]+sum<lowcost[j] && mst[j]!=0)//此点与最⼩点有联系,并且+sum<lowcost 并且此点没有被标记,则赋值给lowcost {lowcost[j]=graph[minid][j]+sum;}}}}int main(){int n,m;int start,end;int graph[MAX][MAX];cin>>n>>m>>start>>end;//初始化图Gfor(int i=1;i<=n;i++){for(int j=1;j<=n;j++){graph[i][j]=MAXCOST;}}//构建图Gfor(int k=1;k<=m;k++){int i,j,cost;cin>>i>>j>>cost;graph[i][j]=cost;graph[j][i]=cost;}prim(graph,n,start,end); return0;}。
最短路问题之Dijkstra算法题⽬: 在上⼀篇博客的基础上,这是另⼀种⽅法求最短路径的问题。
Dijkstra(迪杰斯特拉)算法:找到最短距离已经确定的点,从它出发更新相邻顶点的最短距离。
此后不再关⼼前⾯已经确定的“最短距离已经确定的点”。
Dijkstra算法采⽤的是⼀种贪⼼的策略,声明⼀个数组dis来保存源点到各个顶点的最短距离和⼀个保存已经找到了最短路径的顶点的集合:T,初始时,原点 s 的路径权重被赋为 0 (dis[s] = 0)。
若对于顶点 s 存在能直接到达的边(s,m),则把dis[m]设为w(s, m),同时把所有其他(s不能直接到达的)顶点的路径长度设为⽆穷⼤。
初始时,集合T只有顶点s。
然后,从dis数组选择最⼩值,则该值就是源点s到该值对应的顶点的最短路径,并且把该点加⼊到T中,OK,此时完成⼀个顶点,然后,我们需要看看新加⼊的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否⽐源点直接到达短,如果是,那么就替换这些顶点在dis中的值。
然后,⼜从dis中找出最⼩值,重复上述动作,直到T中包含了图的所有顶点。
代码:1import java.util.HashSet;2import java.util.Set;34public class图的最短路问题_Dijkstra {5public static void main(String[] args) {6int s = 1;7int[] shortestPath = shortestPath(s);89for (int i = 0; i < prev.length; i++) {10 System.out.println((char) ('A' + s) + "到" + (char) ('A' + i) + "的路径");11 System.out.print((char) ('A' + i) + "<-");12int j = prev[i];13while (j != s) {14 System.out.print((char) ('A' + j) + "<-");15 j = prev[j];16 }17 System.out.print((char) ('A' + j));18 System.out.println(":" + shortestPath[i]);19 }20 }2122static int[] prev;2324/**25 * 求起点到各顶点的最短距离26 *27 * @param s 起点28 * @return29*/30private static int[] shortestPath(int s) {31// 顶点个数32int n = graph.length;33// 记录每个点的前驱34 prev = new int[n];35// ⼀定要初始化,源点的前驱是⾃⾝36 prev[s] = s;37// 记录s到各顶点的最短距离38int[] d = new int[n];39 d[s] = 0;// ⾃⼰到⾃⼰的距离为040// 记录已经找到最短距离的顶点41 Set<Integer> T = new HashSet<>();42 T.add(s);4344/*-第⼀步:直接可达的顶点,⽤距离来初始化d,d[s]=0,可直达的把距离记录下来作为待定值-*/45for (int i = 0; i < n; i++) {46if (i != s && graph[s][i] == 0)47 d[i] = Integer.MAX_VALUE;// 不可直达的顶点,先以最⼤整数作为待定值48if (i != s && graph[s][i] > 0) {49 d[i] = graph[s][i]; // 可直达的顶点,以直达距离作为待定值50 prev[i] = s; // 可直达的顶点,其前驱是源点51 }52 }53// Util.print(d);5455while (T.size() < n) {56/*-第⼆步:从待定的距离表中找到最⼩值,这个值可以作为确定值,为什么?-*/57int min = minIndex(d, T);58 T.add(min);59if (T.size() == n)60break;61/*-第三步,看这个新确定的顶点的出度,看看从源点出发是经过这个顶点到其邻居近还是直达更近,如果更近就要更新-*/ 62// 扫描index的邻居63for (int neighbor = 0; neighbor < n; neighbor++) {64int cost = graph[min][neighbor];65// 更新66if (cost > 0 && d[neighbor] > d[min] + cost) {67 d[neighbor] = d[min] + cost;68 prev[neighbor] = min; // 更新最短路后,要更新i这个点的前驱69 }70 }71 }72return d;73 }7475/**76 * 从未确定的点⾥⾯找⼀个最⼩的77 *78 * @param d79 * @param t 已确定了最短距离的顶点集80 * @return81*/82private static int minIndex(int[] d, Set<Integer> t) {83int index = -1;84int min = Integer.MAX_VALUE;85for (int i = 0; i < d.length; i++) {86if (!t.contains(i) && d[i] < min) {87 min = d[i];88 index = i;89 }90 }91return index;92 }9394static int[][] graph = {95 { 0, 2, 5, 0, 0, 0, 0 },96 { 2, 0, 4, 6, 10, 0, 0 },97 { 5, 4, 0, 2, 0, 0, 0 },98 { 0, 6, 2, 0, 0, 1, 0 },99 { 0, 10, 0, 0, 0, 3, 5 },100 { 0, 0, 0, 1, 3, 0, 9 },101 { 0, 0, 0, 0, 5, 9, 0 }102 };103 }结果: 例题,POJ-1502。
单源最短路-dijkstra算法及其优化dijkstra算法及其优化题⽬描述:给定⼀个 n 个点 m 条边的有向图,图中可能存在重边和⾃环,所有边权均为正值。
请你求出 1 号点到 n 号点的最短距离,如果⽆法从 1 号点⾛到 n 号点,则输出 −1。
输⼊格式第⼀⾏包含整数 n 和 m。
接下来 m ⾏每⾏包含三个整数 x,y,z表⽰存在⼀条从点 x 到点 y 的有向边,边长为 z。
输出格式输出⼀个整数,表⽰ 1号点到 n 号点的最短距离。
如果路径不存在,则输出 −1。
数据范围1≤n≤500 1≤m≤10^5 图中涉及边长均不超过10000。
输⼊样例:3 31 2 22 3 11 3 4输出样例:3分析:鉴于n的数据规模⽐较⼩,可⽤朴素迪杰斯特拉算法(适⽤于稠密图)算法时间复杂度O(n^2)code:朴素dijkstra算法#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N = 510;int g[N][N];int dist[N];bool st[N];int n,m;int Dijkstra(){memset(dist,0x3f,sizeof dist);dist[1] = 0;//迭代n次,每次找到⼀个点,⽤它来更新它的可达点到起点的距离。
for(int i=0;i<n;i++){int t = -1;//总是选出当前最短路还没有确定的点中到起点最近的点,并⽤它来更新它的可达点到起点的距离。
(这是迪杰斯特拉算法的核⼼思想--贪⼼) //下⾯是找到当前没有确定最短路的点⾥到起点距离最短的点。
for(int j=1;j<=n;j++){if(!st[j]&&(t==-1||dist[j]<dist[t]))t = j;}st[t] = true;//更新可达点for(int j=1;j<=n;j++) dist[j] = min(dist[j],dist[t] + g[t][j]);}if(dist[n]==0x3f3f3f3f) return -1;return dist[n];}int main(){scanf("%d%d%d",&x,&y,&z);g[x][y] = min(g[x][y],z);}int t = Dijkstra();printf("%d\n",t);return 0;}分析:同⼀题,如果n的数据规模增⼤⾄10^5那么,对于这种稀疏图,可以采⽤堆优化策略的dijkstra算法来求解代码如下://堆优化版dijkstra算法。
迪杰斯特拉(Dijkstra)算法描述及理解Dijkstra算法是⼀种计算单源最短⽆负边路径问题的常⽤算法之⼀,时间复杂度为O(n2)算法描述如下:dis[v]表⽰s到v的距离,pre[v]为v的前驱结点,⽤以输出路径,vis[v]表⽰该点最短路径是否已经确认初始化:dis[v]=INT dis[s]=0 pre[s]=0 执⾏n次 在没有确定的点中找到⼀个路径最短的,并修改为已经确认 通过这个点修改其他所有没有确定的点 直到所有点已经确认为最短路径,退出循环现在证明算法的正确性:⾸先,我们说明两条性质:1.确定任何⼀个点为最短路径时,前驱p⼀定已经是最短路径(假设源点的前驱是它本⾝)。
2.任意时刻在还没有确定最短路径的点的集合中路径最短的点就是可以被确定的点。
稍微证明⼀下这两条性质(反证法):证明1:假如前驱p还不是最短路径,那么显然当p是最短路径时到当前节点的路径更短,即不是最短路径的节点所确定的节点⼀定不是最短路径(好像很显然)证明2:为了⽅便描述,我们定义已经确定的点为⽩点,没有确定的点为蓝点。
若是蓝点中路径最短x还不能确定为⽩点,那么x的最短路径上必定存在⼀个蓝点y。
即dis[x]>dis[y]+edge[y][x]。
⽽dis[y]处于两种状态:(1)dis[y]已经是y点的最短路径,那么显然与dis[x]为蓝点中最短的相⽭盾。
(2)dis[y]还不是y点的最短路径,那么它的前驱显然是另外⼀个蓝点,即dis[y]>=dis[x](这⾥省略了⼀些步骤,不过⾃⼰稍微想⼀下,我觉得挺显然的),也⽭盾。
综上,性质2得证。
回过头再看我们的算法:在刚开始的时候,⾸先确定的最短路(就是直接和源点相连的点)进⼊⽩点集合,满⾜性质1,2。
此后每个过程都满⾜以上两个性质,所以算法正确。
算法实现:1 memset(vis,0,sizeof(vis));2 vis[s]=1;3 dis[s]=0;4 for(int i=1;i<n;i++)5 {6 int m=INT_MAX;7 int k=0;8 for(int j=1;j<=n;j++)9 {10 if(!vis[j] && dis[j]<m)11 {12 m=dis[j];13 k=j;14 }15 }16 if(k==0)17 break;18 vis[k]=1;19 for(int j=1;j<=n;j++)20 {21 if(dis[k]+e[k][j]<dis[j])22 dis[j]=dis[k]+e[k];23 }24 }View Code。