在我为0/1背包和无边背包检查的所有DP解决方案中,解决方案方法总是这样定义:
0/1背包:通过采取第n项或排除第n项来最大化总价值。例如,0/1 knapsack
无界背包:通过将第n个项目视为最后选择的项目,或将(n-1)项目视为最后选择的项目等来最大化总值等。例如,{{3} }
但是无界背包也可以使用0/1背包的逻辑来解决,并进行微调。我的意思是,对于0/1背包,我们执行以下操作(使用第一个链接中的代码):
return max( val[n-1] + knapSack(W-wt[n-1], wt, val, n-1),
knapSack(W, wt, val, n-1)
);
请注意,在我们包含wt[n-1]
的情况下,我们将数组的大小减少1.这意味着wt[n-1]
现在已用尽,因此无法再次使用。但是如果在无限制的情况下,我们不会将数组大小减少1(这意味着可以再次使用wt[n-1]
),稍微修改后的重复关系可以正常工作:
return max( val[n-1] + knapSack(W-wt[n-1], wt, val, n),
knapSack(W, wt, val, n-1)
);
为什么这种无边背包的方法从未在任何地方提到过?实际上unbounded knapsack它明确地说,我们不能使用与无限制的0/1背包相同的逻辑。摘录自该链接:
Observation:
I can never exhaust any item because there are an unbounded supply of items.
Therefore:
The technique used in the 0,1 knapsack problem cannot be used.
但我不能反驳我上面提到的解决方案不会起作用。这个想法来自here问题,你需要计算一定数量的方法来改变给定的数量,假设有无限的硬币供应。
所以我的问题是为什么我在这里提出的方法,从未用于无边背包或至少从未提及任何地方?任何人都可以帮助我证明或反驳这种方法吗?提前谢谢!
答案 0 :(得分:0)
在每个递归调用中,该函数都会迭代所有可用的权重,以查看是否可以包含它,如果可以,则将其值累加到当前递归调用的max_val中。在调用结束时,如果我们能够得到一个值,那么它将返回一个标志,告知已找到解决方案,并将maxSoFar设置为max_value。
#include<bits/stdc++.h>
using namespace std;
// Returns the maximum value with knapsack of
// W capacity
int unboundedKnapsack(int W, int n, int val[], int wt[], int &maxValue)
{
// dp[i] is going to store maximum value
// with knapsack capacity i.
if( W == 0)
return true;
int maxSoFar = INT_MIN;
bool foundASeries = false;
for(int i = 0; i < n; i++)
{
if(W >= wt[i])
{
maxValue = 0;
if(unboundedKnapsack(W-wt[i], n, val, wt, maxValue))
{
foundASeries = true;
maxSoFar = max(maxSoFar, maxValue + val[i]);
}
}
}
maxValue = maxSoFar;
return foundASeries;
}
// Driver program
int main()
{
int W = 8;
int val[] = {10, 40, 50, 70};
int wt[] = {1, 3, 4, 5};
int maxValue = 0;
int n = sizeof(val)/sizeof(val[0]);
cout << unboundedKnapsack(W, n, val, wt, maxValue)<<endl;
cout<< "max value is "<<maxValue;
return 0;
}
答案 1 :(得分:0)
如果你将在无界背包中使用这种方法,那么程序的空间复杂度将是 O(n*W),如果你将使用无处不在的方法,那么它将是 O(n+w) ,其中 n是没有。件数,W 是总重量。
答案 2 :(得分:0)
您不会在任何地方找到您提到的解决方案,因为您的解决方案不是动态编程方法。在您的代码中,它重新评估了动态编程中不应发生的子情况。 如果你愿意,你可以试试这个代码,与你的代码相同,但它遵循动态编程规则
def UnboundedKnapSack2(wt, val, n, capacity):
global dp
if dp[n][capacity] != -1:
return dp[n][capacity]
else:
if n == 0 or capacity <= 0:
dp[n][capacity] = 0
return dp[n][capacity]
elif wt[n - 1] <= capacity:
dp[n][capacity] = max(
val[n - 1] + UnboundedKnapSack(wt, val, n, capacity - wt[n - 1]),
UnboundedKnapSack(wt, val, n - 1, capacity),
)
return dp[n][capacity]
else:
dp[n][capacity] = UnboundedKnapSack(wt, val, n - 1, capacity)
return dp[n][capacity]
weight = [1, 3, 4, 5]
values = [10, 40, 50, 70]
capacity = 8
dp = [[-1 for i in range(capacity + 1)] for j in range(len(weight) + 1)]
print(UnboundedKnapSack2(weight, values, len(weight), capacity))
这不是您问题的唯一解决方案,还有其他完全不使用递归的动态编程代码。
def UnboundedKnapSack3(wt, val, capacity):
n = len(wt)
dp = [[0 for i in range(capacity + 1)] for j in range(n + 1)]
for i in range(n + 1):
for j in range(capacity + 1):
if i == 0 or j == 0:
dp[i][j] = 0
elif j >= wt[i - 1]:
dp[i][j] = max(val[i - 1] + dp[i][j - wt[i - 1]], dp[i - 1][j])
else:
dp[i][j] = dp[i - 1][j]
return dp[-1][-1]
print(UnboundedKnapSack3([1, 3, 4, 5], [10, 40, 50, 70], 8))
使用您喜欢的任何一个,但确保不应重新计算重叠的子问题。