多起点,多终点的最短路径问题
问题背景
- 在实例中经常会遇到路径选择问题,n个起点 S 1 , S 2 , . . . , S N S_1,S_2,...,S_N S1,S2,...,SN,n个终点 T 1 , T 2 , . . . , T N T_1,T_2,...,T_N T1,T2,...,TN,其余结点是途经结点,结点之间用边相连,边上的整数表示长度。
- 问题:给定道路图,在所有起点到终点的路径中找一条长度最短的路径。
蛮力算法
穷举每一个起点到每一个终点的所有可能路径,然后计算每条路径的长度,从中找出最短路径。每条路径对于上述实例,每条路径由4条边组成,除了上下最上,最下两条边的某些结点以外,位于中间的结点都有2条边可选。
起点个数m,n为每条路径长度,也就是路网的层数。那么从起点到终点的路径大致达到
O
(
m
2
n
)
O(m2^n)
O(m2n)量级。
动态规划
求解过程
从终点往起点回推,把求解过程分为4步,每一步对应的子问题的终点不变,但起点逐步前移,使得前步已经求解的问题恰好是后面新问题的子问题,到最后一步求解的是最大的子问题,正好是原始问题。
具体来说所有子问题的终点都是
T
m
T_m
Tm(m=1,2,…,5)。但起点不同
- 第一步对应子问题的起点是 C l C_l Cl(l=1,2,3,4)
- 第二步对应的子问题的起点是 B k B_k Bk(k=1,2,3,4,5)
- 第三步对应的子问题的起点是 A j A_j Aj(j=1,2,3,4)
- 第四步对应的子问题的起点是 S i S_i Si(i=1,2,3,4,5)。这实际上就是原问题
每一步需要求解的是当前起点到终点的最短路径及其长度。
注意:计算完之后要标记在图上,便于追踪。
- 第一步要确定任何 C l C_l Cl到终点的最短路径。先看C1,再看C2…
- 第二步要确定从任何 B k B_k Bk到终点的最短路径: F ( B k ) = min l { B k C l + F ( C l ) } F(B_k)=\displaystyle\min_l\{B_kC_l+F(C_l)\} F(Bk)=lmin{BkCl+F(Cl)}
- 类似的完成后两部递推判断:
- F ( A j ) = min k { A j B k + F ( B k ) } F(A_j)=\displaystyle\min_k\{A_jB_k+F(B_k)\} F(Aj)=kmin{AjBk+F(Bk)}
- F ( S i ) = min j { S i A j + F ( A j ) } F(S_i)=\displaystyle\min_j\{S_iA_j+F(A_j)\} F(Si)=jmin{SiAj+F(Aj)}
每个结点标记的解释:u/d
代表路径方向,后面的数值代表从这个结点作为出发点到达终点所走的路径的最小值。
u代表从这个位置向up
(上)走,d代表从这个位置向down
(下)走
总结归纳及时间复杂度分析 O ( m n ) O(mn) O(mn)
与蛮力算法相比,这种算法的好处是:
在判断时只考虑由前面子问题的最优解(是当前子问题最优解的组成部分)可能的延伸结果,从而把许多不可能称为最优解的部分路径今早从搜索中删除,因此能够提高效率。
根据上面的递推公式,除终点外,对每个结点只需要做2次加法(对
C
l
C_l
Cl层结点不做加法)和1次比较,因此算法时间复杂度可以降到
O
(
m
n
)
O(mn)
O(mn),其中m代表每层的结点个数,n是层数。