Graph-Example1-全部最短路径

全部最短路径的表示方式

如果用树来表示图中点A到点B的最短路径,从每个叶子节点B,往上追溯可以获取到其中一个最短路径。即对树进行DFS遍历可以找到全部最短路径。

那么这个树会有什么特点?

1. 树的根点都是A,叶子节点是B
2. 叶子节点的父节点,即叶子节点B。(因为图全部边的权重>1)
3. 如果相同的节点层数不同,则将相同的节点从树中剥离形成的子树也满足上面两个特性。
   比如下图就不合法,因为其子树(即节点1->3的最短路径树不满足特性2,不合法)
4. 如果相同的节点层数相同,其父节点链必定有一个节点不相同。

在这里插入图片描述

求单源最短路径和求单源全部最短路径的关系

(先去看单源最短路径算法)
单源最短路径算法的精髓在于松弛操作。将图节点S分成两部分,U和V。

  1. (初始步)U的节点是已经求出最短路径的节点,初始为原点。
    V的节点是还未求出最短路径的节点。

  2. 对每个节点 u ∈ U u \in U uU对每个节点 v ∈ V v \in V vV进行松弛操作。

  3. 挑选出当前最短的节点,加入U,从V中去掉。

  4. 如果U!=S,则继续进行2。

U中节点因为2操作一直保持着一个性质:

对于任意 u ∈ U u \in U uU,从原点A到节点u的最短距离已经求出。

为什么可以保持这个性质?

可以把U想像成一个长着很多毛的蛋,将要加入节点U的节点v,与U中某节点u的形成边(u,v)是所有蛋伸出的毛中最短的,进而推得u的最短路径节点序列后加v节点,就是v的最短路径。那么如果存在一个全局路径,使得 u i , v j , . . . v u_i,v_{j},...v ui,vj,...v,使得路径和小于边(u,v),根据权重大于0,可得边 ( u i , v j ) < ( u , v ) (u_i,v_j)< (u,v) (uivj)<(u,v),
那么边(u,v)就不是最短边了。跟假设边(u,v)是所有蛋伸出的毛中最短的是冲突的。

在这里插入图片描述

那么求一条最短路径是这样,求所有最短路径呢?

求一条和求多条最后求出的最短路径的值都是一样的。最短路径变多了。

原来一条的时候,假如将v加入集合U的时候,原点到v的最短路径就求出来了,即

u的最短路径 ( u s , u i , u i + 1 , . . . u ) (u_s,u_i,u_{i+1},...u) (us,ui,ui+1,...u)后面加上节点v, ( u s , u i , u i + 1 , . . . u , v ) (u_s,u_i,u_{i+1},...u,v) (us,ui,ui+1,...u,v)为源点 u s − > v u_s->v us>v的最短路径。

那么如果节点v加入U时,有假设 u s − > u u_s->u us>u的所有最短路径已经求出来了,那么如果所有最短路径用树表示的话,就将u的最短路径树的叶子节点下加v组成树A,和v当前的最短路径树B做合并(操作有点麻烦),就可以求出到v的所有最短路径。
此时将v加入U,则可以保持对于任意 u ∈ U u \in U uU,u的全部路径已经求解完毕的性质。

下面来证明下假设:

对于任意 u ∈ U u \in U uU,u的全部最短路径都已经求出来了。

还是利用反证法,如果v要加入集合U,有没有可能存在v的全部最短路径包含U之外(即集合V中)的节点?还是看长毛蛋的证明,如果最短路径有V中的节点,那么v就不是离蛋最近的节点。最短路径不含V中节点,那么节点v的全部最短路径都由当前U中的节点组成(彼时彼刻,恰如此时此刻)。

最短路径树怎么演化?

松弛命中是什么?

D u + w ( u , v ) < D v D_u+w(u,v)<D_v Du+w(u,v)<Dv
D u 为 节 点 u 的 最 短 距 离 , w ( u , v ) 是 边 ( u , v ) 权 重 D_u为节点u的最短距离,w(u,v)是边(u,v)权重 Duuw(u,v)(u,v)

在求一条最短路径时,如果出现松弛命中,那么你会用u的最短路径后加节点v。但是求多条就不是了。

此时松弛命中会出现两种情况:

i) D u + w ( u , v ) < D v D_u+w(u,v)<D_v Du+w(u,v)<Dv

这种情况下,松弛操作计算出经过节点u,可以使到节点v路径更短。直接在u的最短路径树上加v叶子。

在这里插入图片描述

ii) D u + w ( u , v ) = D v D_u+w(u,v) = D_v Du+w(u,v)=Dv

出现相同的最短路径,这个时候就麻烦,得合并树。

比如
在这里插入图片描述
其中原点1到4的全部最短路径为:
在这里插入图片描述
树合并操作是比较麻烦的,之前全部最短路径为:

  1. 1->2->7->6
  2. 1->3->5->7->6

4对6松弛产生产生了同样短的路径,其路径为:

  1. 1->2->4->6
  2. 1->3->5->4->6

这个在草稿纸上画一画,就能写出这个树,可以咋做成算法? 化成图用树存储确实看的明白点,但是用树存就很不香了,要用一个二维数组。每行存一条路径。

这个时候,4对6做松弛,就把4的所有路径后面加6,放入到6的最短路径集合中。

伪码

还是Dijstra算法,只不过对松弛函数做点小小的改变。

  1. (初始步)U的节点是已经求出最短路径的节点,初始为原点。
    V的节点是还未求出最短路径的节点。

令源点 u s u_s us的所有最短路径为 u s u_s us,其他节点所有最短路径为 ( u s , v i ) (u_s,v_i) (us,vi)

  1. 对每个节点 u ∈ U u \in U uU对每个节点 v ∈ V v \in V vV进行松弛操作。

i) 如果松弛未命中,则不做任何操作。
ii) 如果松弛命中(产生更小路径),则将u所有最短路径后添加v,将结果替换为v所有最短路径。
iii) 如果松弛命中(产生等长路径),则将u的所有路径后添加v,将结果追加到为v所有最短路径。

以下是迪杰斯特拉算法的完整代码,使用Matlab编写: ```matlab function [distances, previous] = dijkstra(adjacency_matrix, start_node) % DIJKSTRA Calculates the shortest path between nodes in a graph using the Dijkstra algorithm % [distances, previous] = DIJKSTRA(adjacency_matrix, start_node) returns the distances % from the start_node to each node in the graph and the previous node for each node on the % shortest path from start_node to that node. % % adjacency_matrix is a square matrix representing the weighted edges of the graph % start_node is the index of the starting node % % Example usage: % % >> adjacency_matrix = [0 7 Inf 5; 7 0 8 9; Inf 8 0 Inf; 5 9 Inf 0] % >> [distances, previous] = dijkstra(adjacency_matrix, 1) % distances = % 0 7 15 5 % previous = % 0 1 2 1 % Initialize variables num_nodes = size(adjacency_matrix, 1); visited = false(1, num_nodes); distances = Inf(1, num_nodes); previous = zeros(1, num_nodes); % Set the distance to the start node to 0 distances(start_node) = 0; % Loop through all nodes in the graph for i = 1:num_nodes % Find the node with the smallest distance that has not been visited yet [min_distance, current_node] = min(distances(~visited)); % If all remaining nodes are inaccessible, break out of the loop if isempty(current_node) break; end % Mark the current node as visited visited(current_node) = true; % Loop through all neighbors of the current node for j = 1:num_nodes if adjacency_matrix(current_node, j) ~= Inf && ~visited(j) % Calculate the distance to the neighbor through the current node distance = min_distance + adjacency_matrix(current_node, j); % If the distance is shorter than the current shortest distance to the neighbor, update it if distance < distances(j) distances(j) = distance; previous(j) = current_node; end end end end end ``` 使用方法: 1. 定义一个邻接矩阵,其中 Inf 表示两个节点之间没有边连接 2. 调用 dijkstra 函数,传递邻接矩阵和起始节点的索引作为参数 3. 函数将返回一个距离数组和前驱节点数组,其中距离数组表示从起始节点到每个节点的最短距离,前驱节点数组表示从起始节点到每个节点的最短路径上每个节点的前一个节点的索引,如果不存在前驱节点,则为0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值