如何解决如何从背包问题的 DP 表中导出最大项目数?
我对 1-0 背包问题的算法做了一些改动。 它也计算最大计数(我们可以放入背包)。 我正在使用它来查找
weights: 1,3,4,5,target sum: 10
result: 1,5 (because 1 + 4 + 5 = 10)
weights: 2,9 target sum: 10
result: 2,4 (2 + 3 + 4 = 9,max possible sum <= 10)
我使用 2 个 DP 表:一个用于计算最大可能总和 (dp
),另一个用于计算最大可能数量 (count
)。
问题是:如何从两个表中得出选定的值?
示例:
weights: [3,2,1,3],target_sum: 10
indexes: 0,6
dp:
0: [0,0]
1: [0,3]
2: [0,5]
3: [0,7,8,10]
4: [0,9,10]
5: [0,6,10]
6: [0,10]
7: [0,10]
count:
0: [0,1]
2: [0,2]
3: [0,3]
4: [0,3]
5: [0,4]
6: [0,4]
7: [0,5]
此处,应导出权重为 [3,1]
的项目(因为它们具有最大可能的数量)而不是(例如)[5,3]
。
一些符号解释:
dp
的含义与原始背包问题中的相同:i
- 用于物品,j
用于重量。
dp[i][j]
中的值表示总和 j 的所选项目(权重)的总和。
count
中的每个单元格对应于 dp
并显示最大可能的物品数量(总重量 = dp[i][j]
)
如何有效地导出所选项目?
我知道如何通过从右下角的单元格重建它来从 dp
中导出任何项目(例如,不是它们的最大数量)。
另外,我发现了一个 hack,如果输入被排序,它允许派生项目。
但我正在寻找可以做到这一点而不会感到疼痛的方法。
有可能吗?
构建这两个表的代码无关紧要,但这里是:
def max_subset_sum(ws,target_sum):
n = len(ws)
k = target_sum
dp = [[0] * (k + 1) for _ in range(n + 1)]
count = [[0] * (k + 1) for _ in range(n + 1)]
for i in range(1,n + 1):
for j in range(1,k + 1):
curr_w = ws[i - 1]
if curr_w > j:
dp[i][j] = dp[i - 1][j]
count[i][j] = count[i - 1][j]
else:
tmp = round(dp[i - 1][j - curr_w] + curr_w,2)
if tmp >= dp[i - 1][j]:
dp[i][j] = tmp
count[i][j] = count[i - 1][j - curr_w] + 1
else:
dp[i][j] = dp[i - 1][j]
count[i][j] = count[i - 1][j]
return get_items(dp,k,n,ws)
def get_items(dp,ws):
# The trick which allows to get max amount of items if input is sorted
start = n
while start and dp[start][k] == dp[start - 1][k]:
start -= 1
res = []
w = dp[start][k]
i,j = start,k
while i and w:
if w != dp[i - 1][j]:
res.append(i - 1)
w = round(w - ws[i - 1],2)
j -= ws[i - 1]
i -= 1
return res
另外,我有奇怪的尝试来获得最大数量的物品。
但它产生的结果不正确,总和为 9
: [3,2]
def get_items_incorrect(dp,count,ws):
start = n
res = []
w = dp[start][k]
i,k
while i and w:
# while dp[i][j] < ws[i - 1]:
# i -= 1
while ws[i - 1] > j:
i -= 1
if i < 0:
break
max_count = count[i][j]
max_count_i = i
while i and w == dp[i - 1][j]:
if count[i - 1][j] > max_count:
max_count = count[i - 1][j]
max_count_i = i - 1
i -= 1
res.append(max_count_i - 1)
w = round(w - ws[max_count_i - 1],2)
j -= ws[max_count_i - 1]
i = max_count_i - 1
return res
抱歉阅读太长,感谢您的帮助!
解决方法
看来你把问题复杂化了。这种问题(没有物品成本)可以使用一维列表来解决。最佳情况的权重存储在并行列表中。
填表后,我们寻找最大的占用索引(最大可能的总和
def sol(wts,target):
dp = [-1] * (target + 1)
dp[0] = 0
items = [0] * (target + 1)
wts.sort()
for w in weights:
for i in range(target,w-1,-1):
if (dp[i-w] >= 0) and (dp[i-w] > dp[i]):
dp[i] = dp[i-w] + 1
items[i] = w
last = target
while (last) and (dp[last] < 0):
last -= 1
best = dp[last]
res = []
while (last):
res.append(items[last])
last -= items[last]
return(best,res)
weights = [1,2,3,5,1]
target_sum = 9
print(sol(weights,target_sum))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。