在背包里找到物品

时间:2015-04-19 18:26:00

标签: c# algorithm recursion knapsack-problem

我想在C#中递归地解决背包问题。这是我的代码:

public  int f(int n, int remain)
{
    if (n < 0) return 0;
    if (w[n] > remain)
    {
        //    Thread.VolatileWrite(ref   check[n], 0);
        check[n] = 0;
        return f(n - 1, remain);
    }
    else
    {
        int a = f(n - 1, remain);
        int b = p[n] + f(n - 1, remain - w[n]);
        if (a >= b)
        {
            //   Thread.VolatileWrite(ref   check[n], 0);
            check[n] = 0;
            return a;
        }
        else
        {
            //  Thread.VolatileWrite(ref   check[n], 1);
            check[n] = 1;
            return b;
        }
    }
}

w是一个保存权重的数组,p是一个保存价格的数组。 n是项目数,remain是最大权重。

我的问题在于check数组。我已经使用这个数组来存储将要放入包中的物品,但它总是不起作用,有时解决方案是正确的,有时候不是。我已经尝试了一切,但无法弄明白。我该如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

check数组的用法是错误的,因为它表示最后一个赋值,并且它不必是所选择的赋值。

这是一个反例,解释了为什么它不起作用。

假设:

weights = [1,2]
values = [2,1]
w = 2

现在,让我们来看看会发生什么:

f(1,2):
   f(0,2):
       f(-1,2)  = 0
       a = 0
       f(-1,1) = 0
       b = 2 + 0 = 2
       b>a -> check[0] = 1
    return f(0,2) = 2
    a = 2
    f(0,0):
       w[0] > 0: check[0] = 0
       return f(-1,0) = 0
    return f(0,0) = 0
    b = 1 + 0 = 1
    a > b: check[1] = 0
return  f(1,2) = 2

所以,这个问题的最佳解决方案是2(选择第二个元素),但你的解决方案没有选择元素(check = [0,0])

这是因为check的更改是全局的,而不是调用环境的本地更改,具体而言 - 深层次的分配不依赖于您在更高级别中所做的选择。

要处理它,您可以:

  1. 使您的列表不是全局的,每个递归调用都有自己的 列表的实例。 &#34;父母&#34;呼叫不仅会选择哪个 要采取的价值,但根据这个选择 - 父母也将 选择它将使用的列表,并附加&#34;他的&#34;选择它,然后转发给它的父母。
  2. 切换到DP solution,或模仿DP解决方案,然后使用您创建的表格来确定要按照此主题中的描述选择哪些元素:How to find which elements are in the bag, using Knapsack Algorithm [and not only the bag's value]?