Пусть dp[i, j] = true
если мы можем сделать сумму j
, используя одно число из каждого набора 1, 2, ..., i
.
dp[i, 0] = true for all i
for i = 1 to numSets do
for num = 1 to sets[i].Count do
for j = maxSum - sets[i, num] downto -maxSum do
dp[i, j + sets[i, num]] |= dp[i - 1, j]
Вы можете использовать карту для обработки отрицательных индексов или добавить смещение ксделать их позитивными.maxSum
- это максимальное значение, которое может принять ваша сумма (например, сумма максимумов всех наборов или сумма абсолютных значений минимумов, в зависимости от того, что больше).Могут быть способы обновления maxSum
по мере оптимизации.
Для вашего примера это будет работать так:
(-2, -1, 0), (-1,4), (-2, 2, 3), (-3, -2, 4, 6), (-2)
Итерация по первому набору даст dp[1, -2] = dp[1, -1] = dp[1, 0] = true
.
Итерация за секунду даст dp[2, -3] = true (because dp[2, -2 + -1] |= dp[1, -1] = true), dp[2, -2] = true (because dp[2, -1 + -1] |= dp[1, -1] = true
) и т. Д.
Если dp[numSets, 0] = true
, есть решение, которое вы можете восстановить, отслеживая, какой последний номер вы выбраликаждый dp[i, j]
.
Сложность O(numSets * K * maxSum)
, где K
- количество элементов набора.Это псевдополином.Это может быть достаточно быстро, если ваши значения невелики.Если ваши значения велики, но у вас мало наборов с небольшим количеством элементов, вам лучше использовать грубое отслеживание с помощью обратного отслеживания.