Python 3.x 动态规划:如何将其分解为子问题?
我陷入了这个问题,我需要一些帮助: 给定一个数组Python 3.x 动态规划:如何将其分解为子问题?,python-3.x,algorithm,dynamic-programming,Python 3.x,Algorithm,Dynamic Programming,我陷入了这个问题,我需要一些帮助: 给定一个数组arr,在每个步骤中,必须将1、2或5个单位增加到数组中除一个以外的所有项目(所有项目的单位数量相同)。目标是找到所有项目相等的最小步骤数 第一个示例 arr=[1,1,5] 1) [1 (+2), 1 (+2), 5] = [3, 3, 5] 2) [3 (+2), 3 (+2), 5] = [5, 5, 5] 解决方案:2个步骤 第二个示例 arr=[2,2,3,7] 1) [2 (+1), 2 (+1), 3, 7 (+1)] = [3,
arr
,在每个步骤中,必须将1、2或5个单位增加到数组中除一个以外的所有项目(所有项目的单位数量相同)。目标是找到所有项目相等的最小步骤数
第一个示例
arr=[1,1,5]
1) [1 (+2), 1 (+2), 5] = [3, 3, 5]
2) [3 (+2), 3 (+2), 5] = [5, 5, 5]
解决方案:2个步骤
第二个示例
arr=[2,2,3,7]
1) [2 (+1), 2 (+1), 3, 7 (+1)] = [3, 3, 3, 8]
2) [3 (+5), 3 (+5), 3 (+5), 8] = [8, 8, 8, 8]
解决方案:2个步骤
我试过一些东西,但我真的卡住了 当所有项都相等时,我考虑一个基本情况。在另一种情况下,我尝试通过对数组中除一项之外的每一项增加1、2和5来找到所有可能的解决方案:
def equal(arr):
if (allElementsIdentical(arr)):
return 0
min = sys.maxsize
for i in [1, 2, 5]:
for j in range(len(arr)):
#Increment all items by "i", except item at index "j"
newArr = arr.copy()
for k in range(j):
newArr[k] += i
for k in range(j + 1, len(newArr)):
newArr[k] += i
movements = 1 + equal(newArr)
if movements < min:
min = movements
return min
我最初的做法正确吗?如何正确地将其分解为子问题?如何获得递归关系
(我正在学习Python,因此对语法的任何评论都非常感谢)我们想用一个能产生相同答案但更容易评估的问题来代替这个问题 让动态规划方法更容易评估的诀窍是让相同的结果在很多地方都显示出来。因此,我们必须用规范化的版本来替换这个问题的等价版本 首先,答案并不取决于数组元素的顺序。因此,我们可以用从最小到最大排序的数组替换数组。现在的操作是将
x
添加到除一之外的所有内容中,然后重新排序为规范形式
其次,答案不取决于最小元素的值。所以我们可以从所有条目中减去该值。现在的操作是,我们将x
添加到除一之外的所有内容中,然后重新排序为规范形式,然后从所有内容中减去最小的内容
这大大减少了我们的问题。足够让广度优先搜索有机会。但我们还有一个把戏要耍。这个诀窍是,不管我们应用操作的顺序是什么。因此,我们可以在2次操作之前,在1次操作之前,应用所有的5次操作。有了这个技巧,我们可以用(节点,最后一次\u操作)
替换每个规范化节点,并开始最后一次\u操作
。这是一场胜利的原因是,现在我们有了a*搜索其余部分的上限。该界限是当前步数+ceil(节点[i]/last\u操作)的总和
现在可以通过*搜索解决这个问题。让我们手工做你的例子。使用符号,(总成本、标准化、最后一次操作、步骤)
示例1:[1,1,5]
1) [1 (+2), 1 (+2), 5] = [3, 3, 5]
2) [3 (+2), 3 (+2), 5] = [5, 5, 5]
我们将标准化为[0,0,4]
,最后一次操作为5,成本为0+0+1=1
。没有采取任何步骤。因此,我们从以下方面开始:
(1, [0, 0, 4], 5)
我们把它拿出来,考虑我们的操作。对于操作5,我们得到以下结果:
[0, 0, 4] + [5, 5, 0] = [5, 5, 4] => [0, 1, 1] # cost 1 + 0+1+1 = 3
[0, 0, 4] + [5, 0, 5] = [5, 0, 9] => [0, 5, 9] # cost 1 + 0+1+2 = 4
[0, 0, 4] + [0, 5, 5] = [0, 5, 9] => [0, 5, 9] # cost 1 + 0+1+2 = 4 DUP
对于操作2,我们得到:
[0, 0, 4] + [2, 2, 0] = [2, 2, 4] => [0, 0, 2] # cost 1 + 0+0+1 = 2
[0, 0, 4] + [2, 0, 2] = [2, 0, 4] => [0, 2, 4] # cost 1 + 0+1+2 = 4
[0, 0, 4] + [0, 2, 2] = [0, 2, 4] => [0, 2, 4] # cost 1 + 0+1+2 = 4 DUP
对于操作1,我们得到:
[0, 0, 4] + [1, 1, 0] = [1, 1, 4] => [0, 0, 3] # cost 1 + 0+0+3 = 4
[0, 0, 4] + [1, 0, 1] = [1, 0, 4] => [0, 1, 4] # cost 1 + 0+1+5 = 6
[0, 0, 4] + [0, 1, 1] = [0, 1, 4] => [0, 1, 4] # cost 1 + 0+1+5 = 6 DUP
我们将7个非重复项放入优先级队列,得到的最佳结果如下所示:
(total cost, normalized, last_operation, steps)
( 2, [0,0,2], 2, 1)
然后我们尝试操作2
和1
,当然,我们会发现其中一个结果是[0,0,0]
经过两个步骤。对我来说,除了一个元素之外,向所有元素添加1、2或5似乎更容易理解为从一个元素中减去1、2或5
为了构造递归,我们可以使用直方图并考虑移位任何值将花费它的频率在操作中。由于允许减少1,我们可以轻松地为可能需要将所有值转移到的最低目标设置下限。由于任何其他值都可以达到最低值,因此将所有值下移到
(最低-5)
(正如HackerRank指出的那样),将涉及n
比将所有元素下移到最低值更多的操作,因为我们首先将所有元素下移到最低值,然后对每个元素应用(-5)
这篇社论还指出,将x
移动到目标0的最小操作数k
,可以通过贪婪算法在O(1)中找到
k = x / 5 + (x % 5) / 2 + (x % 5) % 2
由于您要求尝试形成一个循环,在这种情况下,我们需要解决硬币更换问题(硬币[5,2,1]),以使直方图中的每个值达到目标。这些是独立的:我们对每个值应用coin\u change
的顺序没有区别,以找到所需的操作数,然后乘以值的频率。计算所有值达到每个目标的总操作数,我们选择最小值。有类似问题@E.praneth谢谢。我看到了这些帖子,但我想知道是否有可能用动态规划而不是贪婪的方法来解决它。你在一棵无限树上进行深度优先的研究。你挖得太远了。广度优先研究的问题是,在每一个深度,你都会考虑3N的可能性,特别是除了花费的时间之外,还会导致大量的内存。你可以考虑一个A*算法。这里的一个问题是找到一个好的评估函数来评估已经检查过的节点,这些节点可能具有不同的深度。找到解决方案后,可以使用函数(相同?)来限制从当前检查的节点转到解决方案所需的步骤数。
k = x / 5 + (x % 5) / 2 + (x % 5) % 2