せかいや

いまいるここを、おもしろく http://sekai-in-the-box.appspot.com/

【Ruby】【アルゴリズム】ナップザック問題。綺麗なコード。

 
師匠からメールが来たよ。

動的計画法もおさえておいたほうがいいですね

だって。

前にも解いたことあるけどね。

まあ、考えたうちに入らないっていうことかな。


ここを参考に。
最強最速アルゴリズマー養成講座:病みつきになる「動的計画法」、その深淵に迫る (1/4) - ITmedia エンタープライズ


改めて書くとコードがぜんぜん変ってびっくり。
  

問題

幾つかの品物があり、この品物にはそれぞれ重量・価値の2つのパラメータが与えられています。ある一定の重さまで品物を運べるとしたときに、価値の合計の最大値は幾つになるでしょう?

ただし品物は1種類1個しかない。

コード全量

ITEM = {
a: [3, 2],
b: [4, 3],
c: [5, 7],
d: [6, 10],
e: [9, 14]
}
def solve(knapsack)
  ITEM.each do |_, info|
    proposed_cost, proposed_value = info[0], info[1]
    knapsack.size.times do |target_size|
      knapsack[proposed_cost] = proposed_value if knapsack[proposed_cost] < proposed_value
      next if knapsack[target_size + proposed_cost].nil?
      #値の存在するところだけ検査を行う
      next if knapsack[target_size] == 0  #<= (ア)
      candidate_value = knapsack[target_size] + proposed_value
      knapsack[target_size + proposed_cost] = [knapsack[target_size + proposed_cost], candidate_value].max
    end
  end
  knapsack.shift
  knapsack
end
def max_value_with_size(knapsack_size)
  solve(Array.new(knapsack_size+1, 0))
end
p max_value_with_size(20)
p max_value_with_size(20).max

 
■実行結果

[0, 0, 2, 3, 7, 10, 5, 9, 14, 14, 17, 20, 17, 21, 24, 24, 27, 30, 28, 31]
31

 
ポイントは、maxメソッドで、配列内の最大値を取得すること。

(ア)の条件分岐を行っているため、
このアルゴリズムでは、例えばITEMが一個だけだった場合、

ITEM = {
a: [3, 2],
}

こんな風に、「サイズ3の価値は2、サイズ4の価値は0」と表現されてしまう。

[0, 0, 2, 0, 0, 4, 0, 0, 6, 0, 0, 8, 0, 0, 10, 0, 0, 12, 0, 0]

だから最大値を取ります。