私はよく知られているナップザックの問題で遊んでいます。しかし今回は、F# で実装することにしました。この言語を学んでいて、特に興味深いと感じたからです。
アルゴリズムの主要部分を実装することができましたが、バックトラックも必要です。残念ながら、ウェブで見つけたすべての情報は Haskell を使用していましたが、それはわかりません (まだ ;))。
プレースホルダーとして、変更可能な変数を使用してバックトラッキングを実装しました (詳細には触れずに、「組み合わせ (i, k)」は i 個のアイテムと k の容量の部分的なソリューションを返します)。
let output =
List.rev
[
let i = ref N
let k = ref K
// analize items starting with the last one
for item in Array.rev items do
match !k - item.Size with
// if size of i-th item is greater than current capacity...
| x when x < 0 -> i := !i - 1
// ... this means we haven't taken this item
yield 0
// otherwise we've got two cases
| x when x >= 0 -> let v1 = combinations (!i-1, !k) id
let vc = combinations (!i, !k) id
if v1 = vc then
// case 1: item hasn't been taken
i := !i - 1
yield 0
else
// case 2: item is contained in the optimal solution
i := !i - 1
k := x
yield 1
]
List.iter (fun x -> printf "%A " x) output
F# でこれを行うためのより良い方法があると思います (たとえば、計算式を使用する)。これを機能的なスタイルで実装する方法についてのヒントや情報を聞いて、とてもうれしく思います。
最後に: 私は関数型プログラミングに慣れていないことを覚えておいてください。私が見つけたような魔法の表現を避けるようにしてください:
「モナドはエンドファンクターのカテゴリーのモノイドです。何が問題なのですか?」:)