给定一个整数W ,数组val[]和wt[] ,其中val[i]和wt[i]是第 i 个项目的值和权重,任务是计算使用权重不能获得的最大值超过W 。
注意:每个权重可以包含多次。
例子:
Input: W = 4, val[] = {6, 18}, wt[] = {2, 3}
Output: 18
Explaination: The maximum value that can be obtained is 18, by selecting the 2nd item twice.
Input: W = 50, val[] = {6, 18}, wt[] = {2, 3}
Output: 294
朴素的方法:参考上一篇文章,使用传统的无界背包算法解决问题。
时间复杂度: O(N * W)
辅助空间: O(W)
高效的方法:上述方法可以基于以下观察进行优化:
- 假设第i个索引为我们提供了给定数据中每单位重量的最大值,这很容易在O(n) 中找到。
- 对于任何大于或等于wt[i] 的权重 X ,最大可达值将是dp[X – wt[i]] + val[i] 。
- 我们可以使用传统算法计算 dp[]从0到wt[i]的值,我们还可以计算我们可以适合 W 权重的第i 个项目的实例数。
- 所以所需的答案将是val[i] * (W/wt[i]) + dp[W%wt[i]] 。
下面是新算法的实现。
Python3
# Python Program to implement the above approach
from fractions import Fraction
# Function to implement optimized
# Unbounded Knapsack algorithm
def unboundedKnapsackBetter(W, val, wt):
# Stores most dense item
maxDenseIndex = 0
# Find the item with highest unit value
# (if two items have same unit value then choose the lighter item)
for i in range(1, len(val)):
if Fraction(val[i], wt[i]) \
> Fraction(val[maxDenseIndex], wt[maxDenseIndex]) \
or (Fraction(val[i], wt[i]) == Fraction(val[maxDenseIndex], wt[maxDenseIndex]) \
and wt[i] < wt[maxDenseIndex] ):
maxDenseIndex = i
dp = [0 for i in range(W + 1)]
counter = 0
breaked = False
for i in range(W + 1):
for j in range(len(wt)):
if (wt[j] <= i):
dp[i] = max(dp[i], dp[i - wt[j]] + val[j])
if i - wt[maxDenseIndex] >= 0 \
and dp[i] - dp[i-wt[maxDenseIndex]] == val[maxDenseIndex]:
counter += 1
if counter>= wt[maxDenseIndex]:
breaked = True
# print(i)
break
else:
counter = 0
if not breaked:
return dp[W]
else:
start = i - wt[maxDenseIndex] + 1
times = (W - start) // wt[maxDenseIndex]
index = (W - start) % wt[maxDenseIndex] + start
return (times * val[maxDenseIndex] + dp[index])
# Driver Code
W = 100
val = [10, 30, 20]
wt = [5, 10, 15]
print(unboundedKnapsackBetter(W, val, wt))
输出:
300
时间复杂度:O( N + min(wt[i], W) * N)
辅助空间: O(W)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。