问题
⻓江游艇俱乐部在⻓江上设置了 n 个游艇租聘站,游客可以在这些租聘站租 ⽤游艇,然后在下游的任何⼀个租聘站归还。游艇出租站 i 到 j 的租⾦为 r(i, j),1 ≤i< j≤n,设计⼀个算法,计算从出租站 i 到 j 所需的最少租⾦。
输⼊格式: 第 1 ⾏中有 1 个正整数 n(n<=200),表示有 n 个游艇出租站。 接下来的第 2 到第 n ⾏,第 i ⾏向量包含了第 i-1 站到第 i 站,第 i+1 站, … , 第 n 站的租⾦。
输⼊样例:
在这⾥给出⼀组输⼊。例如:
3 5 15 7
样例说明:表示⼀共有 3 个出租站点,其中:第 1 个站点到第 2 个的租⾦为 5,第 1 个站点到第 3 个的租⾦为 15,第 2 个站点到第 3 个的租⾦为 7
输出格式: 输出从游艇出租站 1 到游艇出租站 n 所需的最少租⾦。
输出样例: 在这⾥给出相应的输出。例如:
12
分析
这道题是一道最短路径的问题,可以使用动态规划算法去实现,我们参考迪杰斯特拉算法的思想,子问题就是起始点0到1、2、3……..n的最短路径,让每个点都作为一次中间点,不断更新起始点到其他点的最短路径,于是就可以得到递推关系式dp[i] = min(dp[i], dp[j]+cost[j][i-j-1]),也就是看看直接到i这个点和先经过j这个点再到i这个点谁的花费比较少,最后dp[n-1]就是我们要求的答案。
下面对代码进行一些解释:
cost[i][j]表示从站点i到站点i+j+1的租用游艇的成本。
dp数组被初始化为每个元素的inf(无穷大),除了第一个元素dp[0]被设置为0。dp数组将用于存储到达每个站点的最小成本。
在内部循环中,代码通过考虑从前一个站点到当前站点的所有可能路径来更新dp[i]的值。它使用公式dp[i] = min(dp[i], dp[j]+cost[j][i-j-1])。这里,dp[j]表示到达站点j的最小成本,而cost[j][i-j-1]表示从站点j到站点i的租用游艇的成本。
循环完成后,从1号站到n号站租用游艇的最小成本将存储在dp[n-1]中。
最后,函数返回dp[n-1]的值。
注意:代码假设cost数组已正确填充了租用游艇的成本。索引i和j用于根据站点编号访问cost数组的正确元素。
代码和运行结果
python">def min_cost(n, cost):
# 初始化 dp 数组
dp = [float("inf") for i in range(n)]
dp[0] = 0
# 动态规划,更新 dp 数组
for i in range(1, n):
for j in range(i):
dp[i] = min(dp[i], dp[j]+cost[j][i-j-1]) # 修改此行
# 返回 dp 数组最后一个元素,即从1号站到n号站租用游艇的最少租金
return dp[n-1]
# 主程序
n = int(input("请输入游艇租赁站数量:"))
cost = []
for i in range(n-1):
row = list(map(int, input(f"请输入:").split()))
cost.append(row)
# 最后一个租赁站到自身的租金为0
cost.append([0])
res = min_cost(n, cost)
print(f"游艇出租站 1 到游艇出租{n}站所需的最少租⾦为: {res}")
这道题的思考关键在于联系最短路径算法,让每个点做一次中间点,不断更新初始点到其他点的最短路径。代码关键点在于递推关系式dp[i] = min(dp[i], dp[j]+cost[j][i-j-1])。其中,dp[i]表示从起始点到达站点i的最小成本,dp[j]表示到达站点j的最小成本,而cost[j][i-j-1]表示从站点j到站点i的租用游艇的成本。代码通过考虑从前一个站点到当前站点的所有可能路径,选择其中最小的成本更新dp[i]的值。