私は 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回の繰り返し)が、それを改善する方法がわかりません。
言い換えれば、これは最適な解決策ですか? 私には非常に指数関数的に感じますが、疑似多項式が実際に何を意味するのかを理解していると言ったら嘘をつきます.