LoginSignup
13
7

More than 5 years have passed since last update.

ナップサック問題 #Ruby

Last updated at Posted at 2015-03-07

ナップサック問題

重さと価値がそれぞれwi,viであるようなn個の品物があります。
これらの品物から、重さの総和がWを超えないように選んだ時の価値の総和の
最大値を求めなさい。


#再帰呼び出し

N = 4
ARRAY = [ [2, 3], [1, 2], [3, 4], [2, 2] ]
ARRAY_W = [ 2, 1, 3, 2 ]
ARRAY_V = [ 3, 2, 4, 2 ]
W = 5

def rec(i, j)
  res = 0
  if i == N
    # もう品物は残っていない
    res = 0
  elsif j < ARRAY_W[i]
    #この品物は入らない
    res = rec(i + 1, j)
  else
    #入れない場合と入れる場合の両方を試す
    res = [ rec(i + 1, j), rec(i + 1, j - ARRAY_W[i]) + ARRAY_V[i] ].max
  end
  res
end

puts "#{rec(0, W)}"


#再帰呼び出し(メモ化)


def rec_memo(i, j, memo_arr)
  if memo_arr[i][j] >= 0
    memo_arr[i][j]
  end

  if i == N
    res = 0
  elsif j < ARRAY_W[i]
    res = rec_memo(i + 1, j, memo_arr)
  else # ARRAY_W[i] < j
    res = [ rec_memo(i + 1, j, memo_arr), rec_memo(i + 1, j - ARRAY_W[i], memo_arr) + ARRAY_V[i] ].max
  end
  memo_arr[i][j] = res
end

memo_arr = Array.new(W + 1, Array.new(W + 1, -1))

p "#{rec_memo(0, W, memo_arr)}"

#動的計画法

N = gets.to_i
W = gets.to_i

arr_w = []
arr_v = []

N.times do |i|
  key, value = gets.split(" ").map(&:to_i)
  arr_w << key
  arr_v << value
end

max_cost = 0
dp = Hash.new
dp[0] = 0

N.times do |ind|
  dp_tmp = dp.clone

  dp.each do |key, value|
    total_key = key + arr_w[ind]
    total_value = value + arr_v[ind]

    unless dp_tmp.has_key?(total_key)
      dp_tmp[total_key] = total_value
    end

    if W >= total_key && total_value > max_cost
      max_cost = total_value
    end
  end

  dp = dp_tmp
end

p max_cost

13
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
7