蓝桥杯 | 路径 问题 | python
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点之间没有边相连;如果 a 和 b 的差的绝对值小于等于21,则两个点之间有一条长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无 向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。
运行限制
最大运行时间:1s
最大运行内存: 128M
- 方案一(运行超时)
import math
# 最小公倍数
def lcm(a, b):
return int(a * b / math.gcd(a, b))
# 2021 个结点
n = 2021
# 求邻接矩阵
g = [[0 for i in range(1, n + 2)] for j in range(1, n + 2)] # n+1行n+1列的二维数组,第0行第0列不用
for i in range(1, n + 1):
for j in range(1, n + 1):
if i == j: # 对角线元素都是0
g[i][j] = g[j][i] = 0
elif abs(i - j) <= 21: # 长度为 a 和 b 的最小公倍数的无向边
g[i][j] = g[j][i] = lcm(i, j)
else: # 没边连接,取大数,求最短路径
g[i][j] = 1000000000
# 超过时间限制
# Floyd算法
for k in range(1, n + 1):
for i in range(1, n + 1):
for j in range(1, n + 1):
if g[i][j] > g[i][k] + g[k][j]:
g[i][j] = g[i][k] + g[k][j]
print(g[1][n]) # 输出结点 1 和结点 2021 之间的最短路径长度
- 方案二
'''
Example:n=10,step=4
d[j]:从结点1到结点j的最短路径
'''
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
d[j] | 0 | inf | inf | inf | inf | inf | inf | inf | inf | inf |
i=1 | 0 | 2 | 3 | 4 | 5 | inf | inf | inf | inf | inf |
i=2 | 0 | 2 | 3 | 4 | 5 | 6+2=8 | inf | inf | inf | inf |
i=3 | 0 | 2 | 3 | 4 | 5 | 8 | 21+3=24 | inf | inf | inf |
i=4 | 0 | 2 | 3 | 4 | 5 | 8 | 24 | 8+4=12 | inf | inf |
i=5 | 0 | 2 | 3 | 4 | 5 | 8 | 24 | 12 | 45+5=50 | inf |
i=6 | 0 | 2 | 3 | 4 | 5 | 8 | 24 | 12 | 18+8=26 | 30+8=38 |
i=7 | 0 | 2 | 3 | 4 | 5 | 8 | 24 | 12 | 26 | 38 |
i=8 | 0 | 2 | 3 | 4 | 5 | 8 | 24 | 12 | 26 | 38 |
i=9 | 0 | 2 | 3 | 4 | 5 | 8 | 24 | 12 | 26 | 38 |
import os
import sys
# 请在此输入您的代码
import math
def lcm(x,y):
return x*y//math.gcd(x,y)
n=2021
# d[j]:从结点1到结点j的最短路径
dp=[float('inf')]*(n+1) # 初始化
dp[1]=0 # 从结点1开始走
for i in range(1,n):
for j in range(i+1,i+22): # step=21
if j>n: # 跳出循环
break
dp[j]=min(dp[j],dp[i]+lcm(i,j))
print(dp[n]) # 输出从结点1到结点2021的最短路径长度