ナップサック問題とは価値と重量をもつ n 種類の荷物が与えられたとき、重量の合計が W を超えない範囲で選択した荷物の価値の合計を最大にするにはどのように選べばよいか」という整数計画問題です。

そのなかでも同じものをナップサック問題において各荷物を1つまでしか選ぶことができない問題を 0-1 ナップサック問題 といいいます。

どのようにして解を導き出せばよいのでしょうか?

「1つも荷物を選べない」あるいは「最大重量が 0」であるときには、詰め込める荷物がないので選ばれた荷物の価値の合計を 0 とする。

荷物 iの重さが w を超えている場合は、荷物 iは追加できないから、価値の合計は荷物の添字の上限が1つ前までのものの価値の最大値になる

荷物 iの重さが wを越えていない場合には、品物 iを追加しない場合と追加をする場合の価値のなかから大きいものを選ぶ。

ここでは0-1 ナップサック問題を考えます。

とし、荷物の数nを4,ナップザックの容量maxWeightを5にします。

最初の一行でnとmaxWeightを表わし、次の行から半角区切りでそれぞれの荷物の重さと価値を表わします。

出力は以下のようになります。

まず重さと価値をセットで管理できるようにItemクラスを定義します。

フィールド変数は荷物の種類の数、ナップサックに積めることができる最大重量、Itemオブジェクトのリスト Itemsです。

SetItemsメソッドはフィールド変数に必要な値をセットし、Itemオブジェクトのリスト Itemsにオブジェクトを格納します。

プログラムが開始されたらSetItemsメソッドで必要な値をフィールド変数に格納したあとソートし、ジャグ配列を生成して、上記アルゴリズムにそって値を確定していきます。

ジャグ配列のdp.Last().Last()を調べれば積めることができる荷物の価値の最大値はわかるのですが、どの荷物を入れるのかも表示させます。また上記アルゴリズムにそって値を確定していく様子も可視化します。

最後に配列に追加された荷物は表示されているので、答えからその値だけ減らします。減らした値が上の配列のなかにあればそこから追加された価値だけ減らして上へとたどっていきます。存在しない場合はその上の配列で追加された価値で同じことができないか試します。0までたどることができたらナップサックにいれることができる荷物を取得できたことになります。