《算法导论》笔记(16) 单源最短路径 部分习题

来源:互联网 发布:国外域名证书生成器 编辑:程序博客网 时间:2024/05/17 08:59

习题21.1-3 Bellman-Ford算法改进为m+1次松弛后终止。图中结点若在s->v的路径中则作标记。松弛过程中,若有标记的结点全部不更新v值,则停止。此时松弛次数为m+1趟。

习题21.1-5 松弛方法改为结点已有d值,对其所有入边选择w+ d< d 中最小的代替原有的d,按照Bellman-Ford算法运行V-1趟。

习题21.1-6 寻找权重为负值的环。用2维矩阵保存所有结点之间的最短路径,也包括自己到自己的路径。然后按照Bellman-Ford算法运行V-1趟松弛。L'(i, j)=min{L(i, k)+ w(k, j) },其中L'(i, j)是运行过程中,最新的i结点到j结点的最短路径。L(i, k)是上次运行得到的i结点到任一结点k的最短路径。L(i, i)是自己到自己的最短路径,L(i, i)为负值的结点,即是负值的环路上的结点。

习题24.2-4 计算有向无环图中的路径总数。拓扑排序后,从起点到终点,遍历每个结点同时计算路径数。P(v)=∑P(u),即结点的路径总数等于所有入边的前驱的路径数之和。

习题24.3-6 最可靠的通信链路。与原始的路径权重相加不同,通信链路上不失效的概率应该相乘。则可以将概率取10为底的对数,作为路径权重。然后用一般的单源最短路径算法就可以解决了。

习题24.3-8 权重函数w: {0, 1, 2,..., W},修改Dijkstra算法计算源点到所有结点最短路径,时间为O(W* V+ E)。因为路径权重都是0到W的自然数,所以优先队列可以用计数排序实现。则运行时间为O(W* V+ E)。其中,V*W是结点总数V乘每次从优先队列中取出时的代价W。E是松弛的总次数。

习题24.3-9 上题继续修改,满足运行时间O((V+E)lgW)。最小优先队列的实现方式改为一棵平衡二叉搜索树,每个结点代表0~W之间的一个自然数,插入时每放入一个元素,则结点计数加1,向上将父结点加1,直到根结点。查找时若左子结点的计数>0则向左下移动,否则返回本结点。如此则插入与查找的时间均为O(lgW)。Dijkstra算法需要将遍历V个结点,每次在二叉树中查找一次,并且对E条边每条都有一次插入二叉树操作。则总时间是O((V+ E)* lgW)。

习题24.4-4 单源最短路径问题表示为线性规划问题。对于任意边E(u, v),w(u, v)是从u到v的边的权重,则有方程xv- xu<= w(u, v)。现寻找s到t的最短路径,即xt-xs的最小值。Bellman-Ford算法可以解。

习题24.4-5 修改Bellman-Ford算法,使其能够在O(nm)时间内解决由n个未知变量和m个约束条件构成的差分约束系统。一个可行的方案是,将每个结点赋初值0,从而省略掉初始源点。因为初始源点只有出边,没有入边,所以迭代过程不会影响初始源点以及初始源点到任一点的路径权值。这样可以将边的数量降为m,结点数量降为n,总时间为O(n*m)。

习题24.4-9 Ax<= b为n个变量与m个约束条件的差分约束系统。证明Bellman-Ford算法可以得到max{x} - min{x}的最小值。首先,收敛过程保证了任意结点的权重是满足约束方程的一个解,那么在从初始源点到任意结点的一条路径上,两点i、j之间的权重差值,就是两个解的差值xi- xj 的最小值。遍历所有路径,可以找到在一条路径上的两个结点,他们之间的权重之差是max{x}- min{x}的最小值。

习题24.4-12 与24.4-11基本相似。Ax<= b的差分约束系统,b所有元素为实数,变量中的某给定子集为整数。先用Bellman-Ford算法得到一个实数的可行解。然后按照得到的路径反向遍历,从初始结点开始,每经过一条边,就将后一个结点的权重赋值为前一结点的权重加上路径权重。对于整数的结点,将结点权重取整,然后继续向后遍历。

G(u, v)Bellman-Ford(){  for i=1 to V-1    for each edge(u, v) in G      relax(u, v, w);  if(relaxed) u.p=v; //找到属于最短路径中的路径}DFS_find_path(){  for each vertex v{    add v to v.p.child[]; //路径反向,构成源点到任意点的路径的森林    mark v as unvisited;  }  for each vertex v in source_s.child[] {    mark v as visiting;    insert all v.child[] in stack;  }  while(u=stack.pop()){     insert all u.child[] in stack;    mark u as visiting;    u.d= u.p.d+ w(u, v);     if(u belong in integer_set) u=u]; //向下取整    if(u.child[] all mark as visted) mark u as visited;  }}

习题24.5-8 G(V, E)为有向图,不包含权重为负值的环路。证明所有结点v,存在|V|-1个松弛步骤组成的松弛序列来生成v.d=δ(s, v)。用数学归纳法。首先证明若最短路径只有1条边情况,Initialize_Single_Source(G, s)就可以收敛。假设最短路径有n条边,经过n-1次松弛可以收敛。那么在最短路径为n+1条边的情况下,n-1次松弛得到v的前驱u的最短路径权重u.d,然后多1次松弛可以得到v.d。可见n+1条边的最短路径需松弛n次。全部结点最多需松弛|V|-1次。

思考题24-1 Yen对Bellman-Ford算法的改进。Gf中的任意边(i, j)都满足i< j的偏序关系,那么DFS深度遍历时,i.d>j.d,并且j的后继不可能是i,则Gf中无环,且拓扑排序时i一定在j的前面。Gb同理。

一遍松弛的过程,Gf与Gb都可以得到各自的最短生成路径。G上一条完整的最短路径,最多可以包含|V|-1条边,其中分属于Gf与Gb。可以知道,此完整路径只需要max{edges in Gf, edges in Gb }次松弛。则最多需要|V|/2次松弛可以得到完整的最短路径。

渐近时间要考虑排序的时间。首先是给所有结点一个随机数以确定偏序,时间O(|V|),然后给所有边标记Gf或Gb,时间O(|E|),最后是|V|/2趟松弛,总时间O(|V|+|E|+|V|*|E|/2),比原版Bellman-Ford算法节省了常数时间。

思考题24-2 嵌套盒子问题。可以先对两个盒子的元素排序,然后比较各相同位置的元素,对任意i<= A.size,A[i]< B[i],则A可以嵌套到B内。

最长嵌套盒子序列。所有盒子排序,然后给出一个拓扑排序,顺序基于两个盒子能否嵌套,有嵌套关系的盒子作为一条有向边。这样就转变成了寻找一条最长路径的问题。从起点到终点一趟松弛可以完成。

思考题24-3 套利交易问题。任意两种货币之间的汇率表示为双向的边,权重为汇率r[i, j]和r[j, i]= 1/r[i, j]。寻找一个环路,是否经过所有路径的权重乘积∏r >1。所有r转换为log对数坐标,则相乘转换为相加。然后Bellman-Ford算法寻找一个权重为负的环路即可。

思考题24-5 Karp的最小平均权重环路算法。u= min max(δn(s,v)- δk(s,v))/ (n-k)。对每个结点v,  令δ[k-1](s, u) 是其所有入边的前驱点u的拥有k-1条边的最短路径。则δ[k](s, v)是δ[k-1](s, u) + (u, v)的松弛结果。经过V-1轮松弛,可以得到k为从1到E的全部结点的全部δ[k],并计算出u,时间为O(VE)。

思考题24-6 双调最短路径。因为最短路径都是双调最短路径,所以沿着任意最短路径的边都是权重先增大再减小。松弛时把所有边按照权重增大的顺序松弛一次再按照权重减小的顺序松弛一次,就可以保证任意最短路径上的结点都经历了一次从起点到终点和一次从终点到起点的松弛过程。松弛次数为2就可以得到所有的最短路径。

0 0
原创粉丝点击