使用递归的背包解决方案

时间:2016-11-20 06:45:48

标签: algorithm scala knapsack-problem

我正在尝试使用Scala中的递归解决背包问题,但我的要求是显示选择哪些项目保留在背包中。 availableMoney表示背包尺寸。

我的代码如下:

def knapsack(availableMoney: Int,wt:List[Int],value :List[Int] ,n:Int) : Int= {

  if(n == 0 || availableMoney == 0)  
    return 0
  if (wt(n - 1) > availableMoney) {     
    return knapsack(availableMoney,wt,value, n - 1)
  }
  else {
    var element1 = value(n-1) + knapsack(availableMoney- wt(n-1), wt, value, n-1)
    var element2 = knapsack(availableMoney, wt, value, n-1)

    return max(element1,element2);
  }
}

如何知道选择哪些物品留在背包中?

2 个答案:

答案 0 :(得分:2)

在您的代码中,您已经知道是否选择了当前元素。

如果您选择element1(它高于element2),则会选择最后一个(index = n-1)元素。从根本上说,你没有。

因此,您可以添加另一个从递归调用返回的输出参数,该参数将指示所选元素。

您需要修改所有return ...以便处理它:

  • return 0将成为return (0,[])
  • return knapsack(availableMoney,wt,value, n - 1)保持原样。
  • return max(element1,element2)将返回(element1, list1.add(n-1))(element2, list2),具体取决于哪个更高,elementelement2

另外,如果你想实现动态编程,这个问题讨论了如何返回元素而不仅仅是值:

How to find which elements are in the bag, using Knapsack Algorithm [and not only the bag's value]?

答案 1 :(得分:1)

请考虑接受amit的解决方案作为答案,我只想在此处补充其他解决方案。

在这个解决方案中,当背包解决方案不唯一时,我也会迎合这种情况。

正如amit指出的那样,修改代码以跟踪背包中的元素是很简单的。您的方法应返回tuple而不是背包值,其中第一个条目是背包的“最大值”,第二个条目是背包中的元素列表列表,表示组合背包中的物品。

  • 第一个if对应于递归的终止条件,背包中只有一个可能的组合 - 没有任何元素的背包。
  • 如果第二个if的条件为真,则无法选择项n - 1,因此我们会重复使用下一个项目。
  • 另一方面,如果项n - 1的权重小于availableMoney,那么我们可以在结构中选择项目n - 1(这相当于element1 ),或在项目中留出n - 1项。然后,返回的解决方案应该是两者中较好的一个,或者如果它们给出相同的值,则将它们合并在一起。

以下是修改后的代码版本供您参考:

def knapsack(availableMoney: Int, wt: List[Int], value: List[Int], n: Int): (Int, List[List[Int]]) = {

  if (n == 0 || availableMoney == 0)
    return (0, List[List[Int]](List[Int]()))

  if (wt(n - 1) > availableMoney) {
    return knapsack(availableMoney, wt, value, n - 1)
  } else {
    val recur = knapsack(availableMoney - wt(n - 1), wt, value, n - 1)
    val element1 = (recur._1 + value(n - 1), for (e <- recur._2) yield {e :+ wt(n - 1)})
    val element2 = knapsack(availableMoney, wt, value, n - 1)

    if (element1._1 > element2._1)
      return element1
    else if (element1._1 < element2._1)
      return element2
    else
      return (element1._1, element1._2 ::: element2._2)
  }
}