【发布时间】:2020-05-12 09:27:48
【问题描述】:
当我遇到这个问题时,我正在重温动态规划 (DP)。我设法使用 DP 来确定子集和问题中有多少解决方案。
def SetSum(num_set, num_sum):
#Initialize DP matrix with base cases set to 1
matrix = [[0 for i in range(0, num_sum+1)] for j in range(0, len(num_set)+1)]
for i in range(len(num_set)+1): matrix[i][0] = 1
for i in range(1, len(num_set)+1): #Iterate through set elements
for j in range(1, num_sum+1): #Iterate through sum
if num_set[i-1] > j: #When current element is greater than sum take the previous solution
matrix[i][j] = matrix[i-1][j]
else:
matrix[i][j] = matrix[i-1][j] + matrix[i-1][j-num_set[i-1]]
#Retrieve elements of subsets
subsets = SubSets(matrix, num_set, num_sum)
return matrix[len(num_set)][num_sum]
基于Subset sum - Recover Solution,我使用以下方法检索子集,因为该集合将始终被排序:
def SubSets(matrix, num_set, num):
#Initialize variables
height = len(matrix)
width = num
subset_list = []
s = matrix[0][num-1] #Keeps track of number until a change occurs
for i in range(1, height):
current = matrix[i][width]
if current > s:
s = current #keeps track of changing value
cnt = i -1 #backwards counter, -1 to exclude current value already appended to list
templist = [] #to store current subset
templist.append(num_set[i-1]) #Adds current element to subset
total = num - num_set[i-1] #Initial total will be sum - max element
while cnt > 0: #Loop backwards to find remaining elements
if total >= num_set[cnt-1]: #Takes current element if it is less than total
templist.append(num_set[cnt-1])
total = total - num_set[cnt-1]
cnt = cnt - 1
templist.sort()
subset_list.append(templist) #Add subset to solution set
return subset_list
但是,由于它是一种贪心方法,因此它仅在每个子集的最大元素不同时才有效。如果两个子集具有相同的最大元素,则它只返回具有较大值的那个。因此,对于总和为 10 的元素 [1, 2, 3, 4, 5] 它只返回
[1, 2, 3, 4] , [1, 4, 5]
什么时候应该返回
[1, 2, 3, 4] , [2, 3, 5] , [1, 4, 5]
我可以在 while 循环中添加另一个循环以省略每个元素,但这会增加 O(rows^3) 的复杂性,这可能会超过实际的 DP,O(rows*columns)。是否有另一种方法可以在不增加复杂性的情况下检索子集?还是在 DP 方法发生时跟踪子集?我创建了另一种方法,可以检索 O(rows) 中解决方案子集中的所有唯一元素:
def RecoverSet(matrix, num_set):
height = len(matrix) - 1
width = len(matrix[0]) - 1
subsets = []
while height > 0:
current = matrix[height][width]
top = matrix[height-1][width]
if current > top:
subsets.append(num_set[height-1])
if top == 0:
width = width - num_set[height-1]
height -= 1
return subsets
这将输出 [1, 2, 3, 4, 5]。但是,从中获取实际子集似乎又要重新解决子集问题。关于如何存储所有解决方案子集(不打印它们)的任何想法/建议?
【问题讨论】:
标签: python dynamic-programming subset-sum