算法复习_全结点对的最短路径

全结点对的最短路径

图论基础知识

路径的权重等于路径上相邻节点之间的权重之和。

最短路径 δ ( u , v ) = m i n { w ( p ) : p 是 连 接 u 和 v 的 路 径 } \delta(u,v) = min\{w(p):p是连接u和v的路径\} δ(u,v)=min{w(p):puv}

最优子结构性质:最短路径的子路径也是最短路径。

证明:从u到v的最短路径必然通过一个中间节点,我们可以将路径u->v划分为u->w->v。即p=p1+p2。我们可以断言如果p是最短路径,那么p1也是u到w的最短路径。我们采用剪切-粘贴法证明,我们假设存在w’使得u到w’存在一条更短的路径,那么我们可以剪切掉p1,将p1’粘贴上,构造出了一条比p更短的路径u->w’->v。与p最优的假设矛盾。因此p1是u->w的最优路径。同理p2可证。

三角不等式: δ ( u , v ) ≤ δ ( u , x ) + δ ( x , v ) \delta(u,v) \leq \delta(u,x) + \delta(x,v) δ(u,v)δ(u,x)+δ(x,v)

如果图G包含一条负回路,那么最短路径不存在。(我只要一直绕着回路走,路径会越来越小)

动态规划

为了简化表示,建立nn的邻接矩阵,定义如下:
w i j = { 0 i = j w ( i , j ) ( i , j ) ∈ E + i n f ( i , j ) ∉ E w_{ij} = \left\{ \begin{matrix} 0 \quad i=j \\ w(i,j) \quad (i,j) \in E \\ +inf \quad (i,j) \notin E \end{matrix} \right. wij=0i=jw(i,j)(i,j)E+inf(i,j)/E
输出n
n矩阵D, d i j d_{ij} dij表示点i到j的最短路径。

d i j ( m ) d_{ij} ^{(m)} dij(m)表示从点i到j最多包含m条边的最短路径。可以证明 d i j n − 1 d_{ij}^{n-1} dijn1就是原问题的解。

证明从i到j的最短路径最多包含n-1条边。

因为所有的回路的权重之和都是正数,所以最短路径肯定不包含回路,一条不包含回路的路径最多有n-1条边。

考虑递归公式:

d i j ( m ) d_{ij}^{(m)} dij(m)有两种情况,(1)最多有m-1条边(2)有m条边

(1) d i j ( m ) = d i j ( m − 1 ) + w j j d_{ij}^{(m)} = d_{ij}^{(m-1)} + w_{jj} dij(m)=dij(m1)+wjj

(2)令k为最短路径中j前面的点。 d i j ( m ) = d i k ( m − 1 ) + w k j d_{ij}^{(m)} = d_{ik}^{(m-1)}+ w_{kj} dij(m)=dik(m1)+wkj

综上: d i j ( m ) = m i n 1 ≤ k ≤ n { d i k ( m − 1 ) + w k j } d_{ij}^{(m)} = min_{1\leq k \leq n} \{d_{ik}^{(m-1)} + w_{kj}\} dij(m)=min1kn{dik(m1)+wkj}

时间复杂度 O ( n 4 ) O(n^4) O(n4):总共需要遍历n-1次得到答案,每次遍历需要确定 n 2 n^2 n2个值,每个值需要考虑n种可能。

空间复杂度 O ( n 3 ) O(n^3) O(n3): n-1 个 n * n矩阵。

优化空间复杂度 O ( n 2 ) O(n^2) O(n2):其实每次只需要最初的W 和 D ( m − 1 ) D^{(m-1)} D(m1)

时间效率优化:重复平方

s ≥ 1 , D ( 2 s ) s\geq 1,D^{(2s)} s1,D(2s)可以通过以下方式计算:
d i j ( 2 s ) = m i n 1 ≤ k ≤ n { d i k ( s ) + d k j ( s ) } d_{ij} ^ {(2s)} = min_{1\leq k \leq n} \{d_{ik}^{(s)} + d_{kj}^{(s)}\} dij(2s)=min1kn{dik(s)+dkj(s)}
因此可以按照以下顺序计算 D ( 2 ) , D ( 4 ) , D ( 8 ) , … , D ( 2 [ l o g n ] ) = D ( n ) D^{(2)},D^{(4)},D^{(8)},\dots,D^{(2^{[logn]})} = D^{(n)} D(2),D(4),D(8),,D(2[logn])=D(n)

时间复杂度 O ( n 3 l o g n ) O(n^3logn) O(n3logn)

Floyd-Warshell算法

最短路径的结构:

  • 不会包含同一个节点两次

  • 中间节点要么在最短路径上,要么不在。
    d i j ( k ) = m i n { d i j ( k − 1 ) , d i k ( k − 1 ) + d k j ( k − 1 ) } d_{ij}^{(k)} = min\{d_{ij}^{(k-1)},d_{ik}^{(k-1)} + d_{kj}^{(k-1)}\} dij(k)=min{dij(k1),dik(k1)+dkj(k1)}

  • D ( 0 ) D^{(0)} D(0)就是权重矩阵,可以通过 D ( k − 1 ) D^{(k-1)} D(k1)计算 D ( k ) D^{(k)} D(k)

Floyd_Warshall(w,n)
for i=1 to n
	for j=1 to m
		d[i,j] = w[i,j]
		pred[i,j]=null
for k=1 to n //首先遍历中间节点
	for i=1 to n
		for j=1 to n
			if d[i,j]<d[i,k]+d[k,j]
				d[i,j] = d[i,k] + d[k,j]
				pred[i,j]=k

时间复杂度 Θ ( n 3 ) \Theta(n^3) Θ(n3)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值