我正在玩 Knapsack(没有真正好的理由,只是想去除一些锈迹)并想用我最喜欢的语言实现它
(请不要笑,大学已经有一段时间了,我对 Scala 还很陌生)
这是我的第一次运行(它返回正确的解决方案,但我认为它远非最佳):
import scala.collection.mutable.HashMap
object Main {
def main(args: Array[String]) {
val weights = List(23, 31, 29, 44, 53, 38, 63, 85, 89, 82)
val values = List(92, 57, 49, 68, 60, 43, 67, 84, 87, 72)
val wv = weights zip values
val solver = new KnapSackSolver()
solver.solve(wv, 165)
}
class KnapSackSolver() {
var numberOfIterations = 0
type Item = (Int, Int)
type Items = List[Item]
val cache = new HashMap[(Items, Int), Items]()
def sackValue(s: Items) = if (s.isEmpty) 0 else s.map(_._2).sum
def solve(wv: Items, capacity: Int) = {
numberOfIterations = 0
val solution = knapsack(wv, capacity)
println(s"""|Solution: $solution
|Value: ${sackValue(solution)}
|Number of iterations: $numberOfIterations
""".stripMargin)
solution
}
private[this] def knapsack(wv: Items, capacity: Int): Items = {
numberOfIterations +=1
val cacheKey = (wv, capacity)
if (cache.contains(cacheKey)) {
return cache(cacheKey) //I know, I wrote a return, just wanted an early exit
}
if (capacity <= 0 || wv.isEmpty) {
Nil
} else if (wv.head._1 > capacity) {
knapsack(wv.tail, capacity)
} else {
val sackNotTakingCurrent = knapsack(wv.tail, capacity)
val sackTakingCurrent = knapsack(wv.tail, capacity - wv.head._1) :+ wv.head
val notTakingCurrentValue = sackValue(sackNotTakingCurrent)
val takingCurrentValue = sackValue(sackTakingCurrent)
val ret =
if (notTakingCurrentValue >= takingCurrentValue) sackNotTakingCurrent
else sackTakingCurrent
cache(cacheKey) = ret
ret
}
}
}
}
问题
我幼稚的“缓存”似乎不够好(565 与 534 次迭代),但我不知道如何改进它,我感觉涉及填充大小 itemsXweight 的矩阵,但不知道从哪里开始。
换句话说 - 这是最佳解决方案吗?对我来说感觉非常指数,但如果我说我理解伪多项式的真正含义,我会撒谎......如果这不是最佳解决方案,我怀疑它不是,我错过了什么?