《算法导论》笔记(17) 所有结点对最短路径 部分习题

习题25.1-6 O(n^3)时间内从已经计算出的最短路径权重矩阵L计算出前驱矩阵Π。任意的L[i, j]最短路径,若j结点前驱为k,则必然有L[i, j]= L[i, k]+ w[k, j]。如此可遍历L矩阵的第i行所有元素L[i, k],若L[i, j]= L[i, k]+ w[k, j],表明k是i-> j最短路径的j的前驱结点。

习题25.1-7 在Extend_Shortest_Paths方法中加入记录前驱结点的功能。

extend_shortest_paths(L, W){
for i= 1 to n
  for j=1 to n
    for k=1 to n
      if( L'[i, j]> L[i, k]+ W[k, j] )  { L'[i, j]= L[i, k]+ W[k, j]; P[i, j]=k; }
return L', P
}
slow_all_pairs_shortest_paths(){
  L[1]=W;
  for m=2 to n-1
    L[m], P[m]=extend_shortest_paths(L[m-1])
}

习题25.1-10 找到最短的权重为负值的环路的长度(边数)。最短路径矩阵L中若元素L[i, i]是负值,则表明i在一个负权重的环路中。同时对上面方法找到的前驱矩阵进行查找,得到环路的边数。

习题25.2-4 证明去掉上标的Floyd-Warshall算法是正确的,从而将空间需求降低到Θ(n^2)。对任意k,d[i, j]依赖于d[i, k]和d[k, j],d[i, k]与d[k, j]可能经历了k-1次松弛也可能经历了k次松弛。但不管如何,d[i, j]是中间结点取自{1, 2, ..., k}的一条最短路径。此即循环不变量。则当k取n时,全部d[i, j]均得到了包含所有结点的最短路径。

习题25.2-8 给出一个O(VE)的时间复杂度的算法来计算有向图G(V, E)的传递闭包。对每个点u进行DFS或者BFS,若经过结点v则将T[u, v]标为1。可知最大运行时间为O(VE)。

习题25.3-5 Johnson算法,证明权重为0的环路上每条边的w'(u, v)=0. 首先,若环路只有一条边,首尾只有一个点,边的权重为0,w'为0. 若不止一个结点,因为环路权重为0,则w(u, v)= -w(v, u)。w'(u, v)= w(u, v)+ h(u)- h(v),则当w(u, v)< 0 时,δ(s, v)= δ(s, u)+ w(u, v),或当w(u, v)> 0 时,δ(s, v)= δ(s, u)- w(u, v)。换句话说,δ(s, v)一定包括w(u, v)或 δ(s, u)一定包括w(v, u)。否则会形成负值环路。则h(u)- h(v)= -w(u, v) 或h(v)- h(u)= w(u, v)。则可证得w'(u, v)= w'(v, u)=0。

思考题25-1 动态图的传递闭包。加入一条边(k, l),则扫描传递闭包矩阵中所有元素,只要满足T[u, k]=1同时T[l, v]=1,就将T[u, v] 赋为1。 运行时间O(V^2)。

insert_edge(E(k, l), T) {
for u= 1 to n
  for v= 1 to n
    if T[u, k]==1 and T[l, v]==1 then T[u, v]=1 
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Floyd算法是一种用于求解任意两结点最短路径的动态规划算法。下面是使用C++实现Floyd算法求解最短路径问题的代码示例: ```cpp #include <iostream> #include <vector> #define INF 99999 // 使用Floyd算法求解任意两结点最短路径 void floydWarshall(std::vector<std::vector<int>>& graph, int n) { std::vector<std::vector<int>> dist(n, std::vector<int>(n)); // 初始化距离矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { dist[i][j] = graph[i][j]; } } // 更新距离矩阵 for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (dist[i][k] + dist[k][j] < dist[i][j]) { dist[i][j] = dist[i][k] + dist[k][j]; } } } } // 打印最短路径 std::cout << "最短路径矩阵:" << std::endl; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (dist[i][j] == INF) { std::cout << "INF "; } else { std::cout << dist[i][j] << " "; } } std::cout << std::endl; } } int main() { int n = 4; // 结点数量 std::vector<std::vector<int>> graph = { {0, 5, INF, 10}, {INF, 0, 3, INF}, {INF, INF, 0, 1}, {INF, INF, INF, 0} }; floydWarshall(graph, n); return 0; } ``` 以上代码中,`graph` 是一个邻接矩阵表示的图,`INF` 表示两个结点之间不存在直接连接。`floydWarshall` 函数使用Floyd算法计算任意两结点最短路径,并将结果存储在 `dist` 矩阵中。最后,我们打印出最短路径矩阵。 在 `main` 函数中,我们测试了一个示例图,并输出了最短路径矩阵。 希望这个代码示例能够帮助到你!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值