最短路性质
在图
G
G
G中,记
(
v
i
,
v
j
)
k
(v_i,v_j)_k
(vi,vj)k为点
v
i
,
v
j
v_i, v_j
vi,vj之间的第
k
k
k条路径,
∣
(
v
i
,
v
j
)
k
∣
|(v_i,v_j)_k|
∣(vi,vj)k∣为点
v
i
,
v
j
v_i, v_j
vi,vj之间沿着第
k
k
k条路径的权和。设从点
v
0
v_0
v0到点
v
n
v_n
vn之间的最短路径
(
v
0
,
v
n
)
k
0
(v_0,v_n)_{k_0}
(v0,vn)k0为
v
0
→
.
.
.
→
v
n
,
v_0 \rightarrow ... \rightarrow v_n,
v0→...→vn,
v
i
,
v
j
v_i, v_j
vi,vj是路径中的两点,则有
∣
(
v
i
,
v
j
)
k
0
∣
=
min
∀
k
∣
(
v
i
,
v
j
)
k
∣
,
|(v_i, v_j)_{k_0}| = \min_{\forall k}|(v_i, v_j)_k|,
∣(vi,vj)k0∣=∀kmin∣(vi,vj)k∣,即最短路的任一段也是最短路。
算法步骤
例题
求出图中各点之间的最短距离。
Python代码
import numpy as np
from numpy import inf
# 输入带权距离矩阵
W = np.array([
[0, 5, 2, inf, inf, inf, inf],
[5, 0, inf, 2, 7, inf, inf],
[2, inf, 0, 7, 0, 4, inf],
[inf, 2, 7, 0, 6, 2, inf],
[inf, 7, inf, 6, 0, 1, 3],
[inf, inf, 4, 2, 1, 0, 7],
[inf, inf, inf, inf, 3, 6, 0]
])
# 计算顶点数
N = W.shape[0]
# 给最短距离矩阵赋初值
D_iter = W
# 给路径矩阵赋初值
R_iter = np.zeros([N, N]).astype('int')
for i in range(N):
R_iter[i, :] = list(range(N))
# 算法迭代主体
for k_iter in range(N):
D_new = D_iter
for i in range(N):
for j in range(N):
t = D_iter[i, k_iter] + D_iter[k_iter, j]
if t < D_iter[i, j]:
D_new[i, j] = t
R_iter[i, j] = k_iter
D_iter = D_new
k_iter += 1
# 输出最短距离矩阵和相应的路径矩阵
print('D(', N, ')=')
print(D_iter)
print('R(', N, ')=')
print(R_iter)
# 打印出最短路径和相应的距离
for i in range(N):
for j in range(N):
# 提取点i到点j的最短距离
dist = D_iter[i, j]
# 计算点i到点j的最短路径
if R_iter[i, j] == j:
path = [i, j]
else:
k = R_iter[i, j]
path_1 = [k]
while R_iter[i, k] != k:
k = R_iter[i, k]
path_1 = [k] + path_1
k = R_iter[i, j]
path_2 = []
while R_iter[k, j] != j:
k = R_iter[k, j]
path_2.append(k)
path = [i] + path_1 + path_2 + [j]
# 打印相应信息
print(i + 1, '到', j + 1, '的最短路径为:', path, '长度为:', dist)
结果:
D( 7 )=
[[ 0. 5. 2. 5. 2. 3. 5.]
[ 5. 0. 7. 2. 5. 4. 8.]
[ 2. 5. 0. 3. 0. 1. 3.]
[ 7. 2. 6. 0. 3. 2. 6.]
[ 7. 5. 5. 3. 0. 1. 3.]
[ 6. 4. 4. 2. 1. 0. 4.]
[10. 8. 8. 6. 3. 4. 0.]]
R( 7 )=
[[0 1 2 5 2 4 4]
[0 1 0 3 5 3 5]
[0 5 2 5 4 4 4]
[1 1 5 3 5 5 5]
[5 5 5 5 4 5 6]
[2 3 2 3 4 5 4]
[5 5 5 5 4 4 6]]
1 到 1 的最短路径为: [0, 0] 长度为: 0.0
1 到 2 的最短路径为: [0, 1] 长度为: 5.0
1 到 3 的最短路径为: [0, 2] 长度为: 2.0
1 到 4 的最短路径为: [0, 2, 4, 5, 3] 长度为: 5.0
1 到 5 的最短路径为: [0, 2, 4] 长度为: 2.0
1 到 6 的最短路径为: [0, 2, 4, 5] 长度为: 3.0
1 到 7 的最短路径为: [0, 2, 4, 6] 长度为: 5.0
2 到 1 的最短路径为: [1, 0] 长度为: 5.0
2 到 2 的最短路径为: [1, 1] 长度为: 0.0
2 到 3 的最短路径为: [1, 0, 2] 长度为: 7.0
2 到 4 的最短路径为: [1, 3] 长度为: 2.0
2 到 5 的最短路径为: [1, 3, 5, 4] 长度为: 5.0
2 到 6 的最短路径为: [1, 3, 5] 长度为: 4.0
2 到 7 的最短路径为: [1, 3, 5, 4, 6] 长度为: 8.0
3 到 1 的最短路径为: [2, 0] 长度为: 2.0
3 到 2 的最短路径为: [2, 4, 5, 3, 1] 长度为: 5.0
3 到 3 的最短路径为: [2, 2] 长度为: 0.0
3 到 4 的最短路径为: [2, 4, 5, 3] 长度为: 3.0
3 到 5 的最短路径为: [2, 4] 长度为: 0.0
3 到 6 的最短路径为: [2, 4, 5] 长度为: 1.0
3 到 7 的最短路径为: [2, 4, 6] 长度为: 3.0
4 到 1 的最短路径为: [3, 1, 0] 长度为: 7.0
4 到 2 的最短路径为: [3, 1] 长度为: 2.0
4 到 3 的最短路径为: [3, 5, 2] 长度为: 6.0
4 到 4 的最短路径为: [3, 3] 长度为: 0.0
4 到 5 的最短路径为: [3, 5, 4] 长度为: 3.0
4 到 6 的最短路径为: [3, 5] 长度为: 2.0
4 到 7 的最短路径为: [3, 5, 4, 6] 长度为: 6.0
5 到 1 的最短路径为: [4, 5, 2, 0] 长度为: 7.0
5 到 2 的最短路径为: [4, 5, 3, 1] 长度为: 5.0
5 到 3 的最短路径为: [4, 5, 2] 长度为: 5.0
5 到 4 的最短路径为: [4, 5, 3] 长度为: 3.0
5 到 5 的最短路径为: [4, 4] 长度为: 0.0
5 到 6 的最短路径为: [4, 5] 长度为: 1.0
5 到 7 的最短路径为: [4, 6] 长度为: 3.0
6 到 1 的最短路径为: [5, 2, 0] 长度为: 6.0
6 到 2 的最短路径为: [5, 3, 1] 长度为: 4.0
6 到 3 的最短路径为: [5, 2] 长度为: 4.0
6 到 4 的最短路径为: [5, 3] 长度为: 2.0
6 到 5 的最短路径为: [5, 4] 长度为: 1.0
6 到 6 的最短路径为: [5, 5] 长度为: 0.0
6 到 7 的最短路径为: [5, 4, 6] 长度为: 4.0
7 到 1 的最短路径为: [6, 4, 5, 2, 0] 长度为: 10.0
7 到 2 的最短路径为: [6, 4, 5, 3, 1] 长度为: 8.0
7 到 3 的最短路径为: [6, 4, 5, 2] 长度为: 8.0
7 到 4 的最短路径为: [6, 4, 5, 3] 长度为: 6.0
7 到 5 的最短路径为: [6, 4] 长度为: 3.0
7 到 6 的最短路径为: [6, 4, 5] 长度为: 4.0
7 到 7 的最短路径为: [6, 6] 长度为: 0.0
Matlab代码
%% 无向图的带权邻接矩阵
D=[
0 5 2 inf inf inf inf
5 0 inf 2 7 inf inf
2 inf 0 7 0 4 inf
inf 2 7 0 6 2 inf
inf 7 inf 6 0 1 3
inf inf 4 2 1 0 7
inf inf inf inf 3 6 0
];
R_iter=[];
for i=1:length(D)
R_iter = [R_iter;1:length(D)];
end
D_iter = D;
k = 1;
while k <= length(D)
D_new = D_iter;
for i=1:length(D)
for j=1:length(D)
t = D_iter(i,k)+D_iter(k,j);
if t < D_iter(i,j)
D_new(i,j) = t;
R_iter(i,j) = k;
end
end
end
D_iter = D_new;
k = k+1;
end
disp(['D(',num2str(k-1),')='])
disp(D_iter) % 打印点到点最短距离矩阵
disp(['R(',num2str(k-1),')='])
disp(R_iter) % 打印路径矩阵
%% 打印出最短路径和相应的距离
for i=1:length(D)
for j=1:length(D)
dist = D_iter(i,j);
if R_iter(i,j) == j
path = [i,j];
else
k = R_iter(i,j);
path_1 = [k];
while R_iter(i,k) ~= k
k = R_iter(i,k);
path_1 = [k, path_1];
end
k = R_iter(i,j);
path_2 = [];
while R_iter(k,j) ~= j
k = R_iter(k,j);
path_2 = [path_2, k];
end
path = [i, path_1, path_2, j];
end
disp([num2str(i),'到',num2str(j),'的最短路为',...
num2str(path),' 长度为',num2str(dist)])
end
end
结果:
D(7)=
0 5 2 5 2 3 5
5 0 7 2 5 4 8
2 5 0 3 0 1 3
7 2 6 0 3 2 6
7 5 5 3 0 1 3
6 4 4 2 1 0 4
10 8 8 6 3 4 0
R(7)=
1 2 3 6 3 5 5
1 2 1 4 6 4 6
1 6 3 6 5 5 5
2 2 6 4 6 6 6
6 6 6 6 5 6 7
3 4 3 4 5 6 5
6 6 6 6 5 5 7
1到1的最短路为1 1 长度为0
1到2的最短路为1 2 长度为5
1到3的最短路为1 3 长度为2
1到4的最短路为1 3 5 6 4 长度为5
1到5的最短路为1 3 5 长度为2
1到6的最短路为1 3 5 6 长度为3
1到7的最短路为1 3 5 7 长度为5
2到1的最短路为2 1 长度为5
2到2的最短路为2 2 长度为0
2到3的最短路为2 1 3 长度为7
2到4的最短路为2 4 长度为2
2到5的最短路为2 4 6 5 长度为5
2到6的最短路为2 4 6 长度为4
2到7的最短路为2 4 6 5 7 长度为8
3到1的最短路为3 1 长度为2
3到2的最短路为3 5 6 4 2 长度为5
3到3的最短路为3 3 长度为0
3到4的最短路为3 5 6 4 长度为3
3到5的最短路为3 5 长度为0
3到6的最短路为3 5 6 长度为1
3到7的最短路为3 5 7 长度为3
4到1的最短路为4 2 1 长度为7
4到2的最短路为4 2 长度为2
4到3的最短路为4 6 3 长度为6
4到4的最短路为4 4 长度为0
4到5的最短路为4 6 5 长度为3
4到6的最短路为4 6 长度为2
4到7的最短路为4 6 5 7 长度为6
5到1的最短路为5 6 3 1 长度为7
5到2的最短路为5 6 4 2 长度为5
5到3的最短路为5 6 3 长度为5
5到4的最短路为5 6 4 长度为3
5到5的最短路为5 5 长度为0
5到6的最短路为5 6 长度为1
5到7的最短路为5 7 长度为3
6到1的最短路为6 3 1 长度为6
6到2的最短路为6 4 2 长度为4
6到3的最短路为6 3 长度为4
6到4的最短路为6 4 长度为2
6到5的最短路为6 5 长度为1
6到6的最短路为6 6 长度为0
6到7的最短路为6 5 7 长度为4
7到1的最短路为7 5 6 3 1 长度为10
7到2的最短路为7 5 6 4 2 长度为8
7到3的最短路为7 5 6 3 长度为8
7到4的最短路为7 5 6 4 长度为6
7到5的最短路为7 5 长度为3
7到6的最短路为7 5 6 长度为4
7到7的最短路为7 7 长度为0