Восстановление подмножеств в задаче о сумме подмножеств — появляются не все подмножества

Освежая динамическое программирование (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

Однако, поскольку это жадный подход, он работает только тогда, когда максимальный элемент каждого подмножества различен. Если два подмножества имеют одинаковый максимальный элемент, он возвращает только тот, у которого больше значение. Итак, для элементов [1, 2, 3, 4, 5] с суммой 10 он возвращает только

[1, 2, 3, 4] , [1, 4, 5]

Когда он должен вернуться

[1, 2, 3, 4] , [2, 3, 5] , [1, 4, 5]

Я мог бы добавить еще один цикл внутри цикла while, чтобы исключить каждый элемент, но это увеличило бы сложность до O (строки ^ 3), что потенциально может быть больше, чем фактический DP, O (строки * столбцы). Есть ли другой способ получить подмножества без увеличения сложности? Или отслеживать подмножества во время подхода DP? Я создал еще один метод, который может получить все уникальные элементы в подмножествах решений за O(строки):

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]. Однако получение из него фактических подмножеств похоже на решение проблемы подмножества заново. Любые идеи/предложения о том, как хранить все подмножества решений (не печатать их)?


person Macroxela    schedule 12.05.2020    source источник