当青训营遇上码上掘金
题目
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
解题思路
看到题目第一思路是用贪心法解决这个问题,但是贪心法有一个缺点,它是一种只考虑眼前情况的策略。由于没有考虑到长远的情况,贪心法并不总是能给出最佳答案。
第二个想法是动态规划,在这道题中,小青只有两种交通方式:步行和公交。其中步行可以进一步或者退一步,而公交只能进不能退,并且每次只能前进2的倍数。观察这些信息,我们可以发现: 当小青处于位置i时,小青到小码家所需要的最短时间f(i)仅取决于f(i-1)、f(i+1)、f(i/2),因此我们可以得到关系式:
在这里我定义了一个数组,用于记录小青处于路程中的某个中间位置时,所需的最短时间。通过一步步的累积,最终确定小青到小码家所需的最短时间。
最终代码实现如下:
# 寻友之旅
def find_friend() -> None:
"""
本实验小青是起点,小码是终点。
以小码的位置K建立数组,小青的位置N作为在数组中的一个数,数组记为arr。
使用动态规划思想,关系式为:
dp[i] = min(dp[i-1], dp[i//2], dp[i+1]) + 1
其中dp定义为从小青到小码的步数
"""
while True:
# N: 小青的位置
N = int(input("请输入小青的位置 N: "))
# K: 小码的位置
K = int(input("请输入小码的位置 K: "))
if N < 0 or K > 100000 or N > K:
print("请输入程序要求的参数")
continue
else:
break
if N == K:
return 0
else:
# 将数组延长10个单位,给步行方式后退一步留下空间
dp = [0 for _ in range(K + 11)]
dp[N] = 0
for i in range(N + 1, K + 1):
if i % 2 == 0 and dp[i+1] > 0:
dp[i] = min(dp[i-1], dp[i//2], dp[i+1]) + 1
elif dp[i+1] > 0:
dp[i] = min(dp[i-1], dp[i+1]) + 1
elif i % 2 == 0:
dp[i] = min(dp[i-1], dp[i//2]) + 1
else:
dp[i] = dp[i-1] + 1
print(f"最少花费{dp[K]}分钟")
if __name__ == "__main__":
find_friend()
同时放上码上掘金的代码。注意:码上掘金的编译器不支持输入,即input()
总结
对于每一个动态规划问题,我们需要首先定义一个数组,用于记录动态规划的中间结果。在这一个过程中,我们需要明确这一个数组需要记录的数据是什么。然后我们需要归纳出动态规划问题具体的问题关系式,接下来就是根据这一个得出的关系式设计代码,得到最后的结果。