知识大全 贪婪算法之——单源最短路径
Posted 路径
篇首语:绝大多数人,在绝大多数时候,都只能靠自己。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 贪婪算法之——单源最短路径相关的知识,希望对你有一定的参考价值。
在这个问题中 给出有向图G 它的每条边都有一个非负的长度(耗费) a [i ][ j ] 路径的长度即为此路径所经过的边的长度之和 对于给定的源顶点s 需找出从它到图中其他任意顶点(称为目的)的最短路径 图 a 给出了一个具有五个顶点的有向图 各边上的数即为长度 假设源顶点s 为 从顶点 出发的最短路径按路径长度顺序列在图 b 中 每条路径前面的数字为路径的长度
利用E Dijkstra发明的贪婪算法可以解决最短路径问题 它通过分步方法求出最短路径 每一步产生一个到达新的目的顶点的最短路径 下一步所能达到的目的顶点通过如下贪婪准则选取 在还未产生最短路径的顶点中 选择路径长度最短的目的顶点 也就是说 D i j k s t r a的方法按路径长度顺序产生最短路径
首先最初产生从s 到它自身的路径 这条路径没有边 其长度为 在贪婪算法的每一步中 产生下一个最短路径 一种方法是在目前已产生的最短路径中加入一条可行的最短的边 结果产生的新路径是原先产生的最短路径加上一条边 这种策略并不总是起作用 另一种方法是在目前产生的每一条最短路径中 考虑加入一条最短的边 再从所有这些边中先选择最短的 这种策略即是D i j k s t r a算法
可以验证按长度顺序产生最短路径时 下一条最短路径总是由一条已产生的最短路径加上一条边形成 实际上 下一条最短路径总是由已产生的最短路径再扩充一条最短的边得到的 且这条路径所到达的顶点其最短路径还未产生 例如在图 中 b 中第二条路径是第一条路径扩充一条边形成的;第三条路径则是第二条路径扩充一条边;第四条路径是第一条路径扩充一条边;第五条路径是第三条路径扩充一条边
通过上述观察可用一种简便的方法来存储最短路径 可以利用数组p p [ i ]给出从s 到达i的路径中顶点i 前面的那个顶点 在本例中p [ : ] = [ ] 从s 到顶点i 的路径可反向创建 从i 出发按p[i] p[p[i]] p[p[p[i]]] 的顺序 直到到达顶点s 或 在本例中 如果从i = 开始 则顶点序列为p[i]= p[ ]= p[ ]= =s 因此路径为
为能方便地按长度递增的顺序产生最短路径 定义d [ i ]为在已产生的最短路径中加入一条最短边的长度 从而使得扩充的路径到达顶点i 最初 仅有从s 到s 的一条长度为 的路径 这时对于每个顶点i d [ i ]等于a [ s ] [ i ](a 是有向图的长度邻接矩阵) 为产生下一条路径 需要选择还未产生最短路径的下一个节点 在这些节点中d值最小的即为下一条路径的终点 当获得一条新的最短路径后 由于新的最短路径可能会产生更小的d值 因此有些顶点的d值可能会发生变化
综上所述 可以得到图 所示的伪代码 ) 将与s 邻接的所有顶点的p 初始化为s 这个初始化用于记录当前可用的最好信息 也就是说 从s 到i 的最短路径 即是由s到它自身那条路径再扩充一条边得到 当找到更短的路径时 p [ i ]值将被更新 若产生了下一条最短路径 需要根据路径的扩充边来更新d 的值
) 初始化d[i ] =a[s] [i ]( ≤i≤n)
对于邻接于s的所有顶点i 置p[i ] =s 对于其余的顶点置p[i ] = ;
对于p[i]≠ 的所有顶点建立L表
) 若L为空 终止 否则转至 )
) 从L中删除d值最小的顶点
) 对于与i 邻接的所有还未到达的顶点j 更新d[ j ]值为m i nd[ j ] d[i ] +a[i ][ j ] ;若d[ j ]发生了变化且j 还未
在L中 则置p[ j ] = 并将j 加入L 转至
图 最短路径算法的描述
数据结构的选择
我们需要为未到达的顶点列表L选择一个数据结构 从L中可以选出d 值最小的顶点 如果L用最小堆(见 节)来维护 则这种选取可在对数时间内完成 由于 ) 的执行次数为O ( n ) 所以所需时间为O ( n l o g n ) 由于扩充一条边产生新的最短路径时 可能使未到达的顶点产生更小的d 值 所以在 ) 中可能需要改变一些d 值 虽然算法中的减操作并不是标准的最小堆操作 但它能在对数时间内完成 由于执行减操作的总次数为 O(有向图中的边数)= O ( n ) 因此执行减操作的总时间为O ( n l o g n )
若L用无序的链表来维护 则 ) 与 ) 花费的时间为O ( n ) ) 的每次执行需O(|L | ) =O( n )的时间 每次减操作需( )的时间(需要减去d[j] 的值 但链表不用改变) 利用无序链表将图 的伪代码细化为程序 其中使用了C h a i n (见程序 )和C h a i n I t e r a t o r类(见程序 )
程序 最短路径程序
template
void AdjacencyWDigraph ::ShortestPaths(int s T d[] int p[])
// 寻找从顶点s出发的最短路径 在d中返回最短距离
// 在p中返回前继顶点
if (s < || s > n) throw OutOfBounds();
Chain L; // 路径可到达顶点的列表
ChainIterator I;
// 初始化d p L
for (int i = ; i <= n; i++)
d[i] = a[s][i];
if (d[i] == NoEdge) p[i] = ;
else p[i] = s;
L I n s e r t ( i ) ;
// 更新d p
while (!L IsEmpty()) // 寻找具有最小d的顶点v
int *v = I Initialize(L);
int *w = I Next();
while (w)
if (d[*w] < d[*v]) v = w;
w = I Next();
// 从L中删除通向顶点v的下一最短路径并更新d
int i = *v;
L D e l e t e ( * v ) ;
for (int j = ; j <= n; j++)
if (a[i][j] != NoEdge && (!p[j] ||
d[j] > d[i] + a[i][j]))
// 减小d [ j ]
d[j] = d[i] + a[i][j];
// 将j加入L
if (!p[j]) L Insert( j);
p[j] = i;
若N o E d g e足够大 使得没有最短路径的长度大于或等于N o E d g e 则最后一个for 循环的i f条件可简化为 if (d[j] > d[i] + a[i][j])) NoEdge 的值应在能使d[j]+a[i][j] 不会产生溢出的范围内
复杂性分析
cha138/Article/program/sjjg/201311/23592相关参考