当前位置: 首页 > 知识库问答 >
问题:

用0/1背包逻辑递归求解无界背包

晋西岭
2023-03-14

在我为0/1背包和无界背包签出的所有DP解决方案中,解决方案方法总是这样定义的:

0/1背包:取第n项或不取第n项,使总价值最大化。例如,0/1背包

无界背包:将第n个物品视为最后挑选的物品,或(n-1)个物品视为最后挑选的物品,使总价值最大化。例如,无界背包

但无界背包也可以使用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)
          );

为什么这种无界背包的方法在任何地方都没有提到?实际上这里它特别指出,对于无界背包,我们不能使用与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.

但是我不能反驳我上面提到的解决方案是行不通的。这个想法来自硬币兑换问题,在这个问题中,假设硬币的供应量是无限的,你必须计算出改变给定数量的方法。

所以我的问题是为什么我在这里提出的方法从未用于无界背包,或者至少从未在任何地方提到过?有人能帮我证明或反驳这种方法吗?提前谢谢!

共有3个答案

江英华
2023-03-14

如果你在无界背包中使用这种方法,那么程序的空间复杂度将是O(n*W),如果你使用到处都给出的方法,那么它将是O(n W),其中n是项数,W是总重。

爱炯
2023-03-14

您不会在任何地方找到您提到的解决方案,因为您的解决方案不是动态编程方法。在您的代码中,它是重新评估动态编程中不应该发生的子案例。如果您愿意,您可以尝试此代码,与您的代码相同,但它遵循动态编程规则


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))

使用您喜欢的方法,但确保不应重新计算重叠的子问题。

况唯
2023-03-14

在每个递归调用中,函数都会遍历所有可用的权重,以查看是否可以包含它,如果可以,则其值将累积到当前递归调用的max\u val中。在调用结束时,如果我们能够获得一个值,那么它将返回一个标志,告诉我们找到了一个解决方案,并将maxSoFar设置为max\u值。

#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;
}
 类似资料:
  • 我试图在Scala中使用递归来解决背包问题,但我的要求是显示选择哪些项目保存在背包中。表示背包大小。 我的代码如下: 如何知道选择哪些物品放在背包里?

  • 我对这个问题有点困惑。作为算法帮助我找到最大的利润从袋。但是这个算法并没有告诉我我应该拿哪一个项目会让我的利润最大。例如 n=4项,背包的容量M=8,利润=[15,10,9,5],重量分别为w=[1,5,3,4],当我解决这个问题时,我得到最大的利润为29 这里是解决方案[http://www.mafy.lut.fi/study/DiscreteOpt/DYNKNAP.pdf] 但是我想知道我应该

  • 我写了一个背包类,我用它来解决背包算法。这个类正在使用动态规划算法来解决这个问题。 我在代码中实现了一些优化,因此我使用线性O(W)空间来找到最大值,但当我试图找到见证时,我仍然需要O(nW)空间来保持布尔表。 有人能告诉我,是否有可能找到背包容量最大、空间较小、复杂度与O(nW)相同的证据,这里W是背包容量。 如果您认为代码中可能还有更多优化,请也告诉他们。

  • 本文向大家介绍C中的0-1背包问题?,包括了C中的0-1背包问题?的使用技巧和注意事项,需要的朋友参考一下 背包是袋子。背包问题是根据物品的值将物品放入袋中的。目的是使袋子内的值最大化。在0-1背包中,您既可以放置物品也可以将其丢弃,没有将物品的某些部分放入背包的概念。 样本问题 重量分布 最大值为65,因此我们将项目2和3放入背包。 0-1背包问题计划 输出结果

  • 本文向大家介绍解决0-1背包问题的C ++程序,包括了解决0-1背包问题的C ++程序的使用技巧和注意事项,需要的朋友参考一下 在0-1背包问题中,给出了一组项目,每个项目都有一个权重和一个值。我们需要确定要包含在集合中的每个项目的数量,以使总重量小于或等于给定的限制,并且总值尽可能大。 输入项 输出结果 算法 范例程式码 输出结果

  • 我正在为即将到来的测试复习,想知道是否有人能重述问题的b部分。这是从分发的复习表中得到的文本,但我不确定b部分到底在问什么。我更直截了当地猜测“生成一个不到0/1背包问题最优值1%的解”是什么意思。 b)[10pts]举了一个有两个对象的例子,说明对分数背包问题使用的相同的贪婪方法(略加修改,如果贪婪方法选择的最后一个对象不适合,则忽略它)得到的解不到0/1背包问题最优解的1%。