【发布时间】:2019-06-22 11:06:09
【问题描述】:
我正在尝试使用动态编程表填充方法来解决优化问题,但我无法在最优子结构中分解问题。
这就是问题所在:
给定一个排序数组,从种子元素开始,你可以将数组减少到只有一个元素。
- 您可以删除除种子之外的数组元素,这被视为 1 步,这会减少数组。
- 您可以将小于种子的数组元素添加到种子。这被视为 1 步。
- 您可以使用以前的方法向种子中添加任意次数。
- 种子可以“消耗”比它少的任何元素。这会减少数组。
例如,这是排序后的数组
3, 20, 50, 100, 400
第一个元素是种子。
第一个元素还不能消耗下一个更大的元素,所以我们需要添加它。根据约束,我们可以在 1 步中添加任何小于种子的内容。所以,假设我们加了 2。
moves = 1
seed = seed + 2
5, 20, 50, 100, 400
还是种子不能消费下一个元素,所以我们加4
moves = 2
seed = seed + 4
9, 20, 50, 100, 400
moves = 3
seed = seed + 8
17, 20, 50, 100, 400
moves = 4
seed = seed + 16
33, 20, 50, 100, 400
现在种子可以“消耗”下一个元素 所以减少的数组变成了
53 (33 + 20) , 50, 100 , 400
53可以消耗50变成103
103, 100, 400
103可以化100变成203
203, 400
203是种子,不能消耗400 所以
moves = 5
seed = seed + 202
405, 400
现在可以消费变成805了
我们也可以简单地删除 400,这将被视为 1 步。
总移动次数 = 5
但还有另一种解决方案,即从数组中删除所有元素(20、50、100、400),这需要 4 次移动。
所以在这种情况下,最小移动数是 4。
尝试从动态规划的角度来考虑它,我可以看到在每一步我们都有两个选择,是消耗元素还是删除元素。似乎要考虑的路径总数是所有 2^n 路径。
但我未能将其分解为重叠的子问题或最优子结构,甚至无法定义递归关系。
动态编程是正确的方法吗?
一些观察:
- 当我们必须向种子添加一些东西时,最好的方法似乎是添加尽可能高的允许值,即种子 - 1
- 一旦我们决定删除一个元素,这意味着后面的元素也将被删除。为什么,因为如果我们决定多次向种子添加对当前元素无效,那么对于下一个更大的元素也是如此。
【问题讨论】:
-
数组的最大大小可以是多少,每个数字可以有多大?
-
你可以使用 (max{given array}+1)* array_size 时间和内存复杂度来解决。
-
我是否理解正确,消费不计入移动?
-
@גלעדברקן 消耗不被认为是一个动作,所以只要有比种子小的元素,它们在 0 个动作中被消耗
-
@user58697 是的,这是正确的
标签: arrays algorithm dynamic-programming