Python动态规划实现疑问:算法4.8中s的取值与f(s)最小化实现
解决动态规划Algorithm 4.8中的最优分割点问题及Python实现
我来帮你理清这个动态规划的逻辑并修正代码问题~你提到的困惑其实是动态规划中「枚举所有可能子问题,选择最优解」的核心步骤,咱们一步步拆解:
先解答你的核心疑惑
为何书中既在for循环中使用s,又要将s设为使f(s)最小的取值?
这里的for循环是枚举所有可能的分割点:当我们要把前t+1个元素(因为x是0索引)分成j+1个区间时,s代表前j个区间的最后一个元素的索引,剩下的s+1到t就是第j+1个区间。
而f(s) = max(r[s][j-1], (x[t]-x[s+1])/2)的含义是:这个分割方案下的「最大代价」(前j个区间的最优最大代价,加上当前区间的代价,取两者的最大值)。我们的目标是找到所有可能分割点中,这个最大代价最小的那个——这正是动态规划「最优子结构」的体现:全局最优解由子问题的最优解组合而来。
你当前的代码问题在于:每次遍历s时直接覆盖r[t][j],最后得到的是最后一个s对应的f(s),而不是所有可能中的最小值,这就偏离了算法的要求。
修正后的Python实现
我调整了代码的核心逻辑,同时修正了几个细节错误,注释里写清楚了每一步的作用:
x = [1,2,5,6,10] k = 3 # 要划分的区间数量 n = len(x) # 用len(x)代替硬编码的5,更灵活 # 初始化r和c矩阵:r记录最优最大代价,c记录各区间的中心点 r = [[0 for _ in range(k)] for _ in range(n)] c = [[[] for _ in range(k)] for _ in range(n)] def Union(lst1, lst2): return lst1 + lst2 for j in range(k): for t in range(n): if j == 0: # j=0时只有1个区间,覆盖x[0]到x[t] r[t][j] = (x[t] - x[0]) / 2 c[t][j] = [(x[t] + x[0]) / 2] else: # 初始化最小代价为无穷大,用来后续比较 min_max_cost = float('inf') best_split_s = -1 # 记录最优分割点s # 遍历所有可能的分割点s:从0到t-1(s是前j-1个区间的最后一个元素索引) for s in range(t): # 计算当前分割点对应的最大代价 current_cost = max(r[s][j-1], (x[t] - x[s+1]) / 2) # 如果当前代价更小,更新最小值和最优分割点 if current_cost < min_max_cost: min_max_cost = current_cost best_split_s = s # 用最优分割点的结果更新r和c r[t][j] = min_max_cost # 当前区间的中心点是(x[t]+x[s+1])/2,合并前j-1个区间的中心点 current_center = (x[t] + x[best_split_s + 1]) / 2 c[t][j] = Union(c[best_split_s][j-1], [current_center]) # 打印结果 print("最优最大代价矩阵r:") for row in r: print([round(val, 2) for val in row]) # 保留两位小数更易读 print("\n各区间中心点矩阵c:") for row in c: print([round(val, 2) for val in row])
关键修改说明
- 初始化逻辑优化:把
c的初始值改为空列表,避免原代码中c[s][j-1] == 0的错误判断(因为c存储的是中心点列表,不是数值0)。 - 最优分割点的寻找:先初始化最小代价为无穷大,遍历所有
s计算代价,只保留最小的那个代价和对应的s,最后再用这个最优s更新r和c。 - 遍历范围修正:原代码中
range(t-1)会漏掉s=0的情况,改为range(t)才能覆盖所有可能的分割点。
运行这段代码后,你就能得到Algorithm4.8要求的最优结果啦~
内容的提问来源于stack exchange,提问作者user10322040
相关产品推荐
相关产品推荐

