class Product
attr_reader :size, :value
def initialize( size, value )
@size = size
@value = value
end
end
class Nap
def initialize( size )
@napValue = Array.new( size, 0 ) # ナップザックの価値
end
def main( products )
# 扱う品物を1つずつ増やしていく
i = 0
while i < products.length
# ナップザックの大きさが j のものに対して
# 品物 i 番を入れてみる
j = products[i].size
while j < @napValue.length
# 品物 i 番を入れてみた場合、新しい価値はどうなるか
newValue = @napValue[j - products[i].size] + products[i].value
if newValue > @napValue[j]
@napValue[j] = newValue
end
j += 1
end
printf "品物#{i + 1}まで使う : "
j = 1
while j < @napValue.length + 1
num = @napValue[j].to_s + " "
if num.size == 2
num = " " + num
end
printf num
j += 1
end
printf "¥n"
i += 1
end
end
end
products = [
Product.new( 2, 2 ), Product.new( 3, 4 ),
Product.new( 5, 7 ), Product.new( 6, 10 ),
Product.new( 9, 14 )
]
nap = Nap.new( 16 )
nap.main( products )
【注】
バックトラック法によるスクリプト、どうも結果がおかしいようです。ごめんなさい。
class SeparatorBackTruck
def initialize
@value = [15, 3, 7, 6, 10, 4, 13, 2, 3, 6]
@separator = 3
@sepPos = Array.new( @separator, 0 )
# 最適な分割とその中のグループの最大和
@bestSepPos = Array.new( @separator, 0 )
@bestSepMaxValue = 10000
end
def separate( pos, num )
# 新しい分割場所を設定
@sepPos[num += 1] = pos
# 分割が全て決まったら
if num == @separator
max = 0
0.upto( @separator ) do |i|
start = ( i == 0 ) ? 0 : @sepPos[i - 1]
last = ( i == @separator ) ? @value.length : @sepPos[i]
k = 0
start.upto( last - 1) do |j|
k += @value[j]
end
if k > max
max = k
end
end
# 最大のグループ和が保存されている和より小さければ
if max < @bestSepMaxValue
@bestSepMaxValue = max
@separator.times do |i|
@bestSepPos[i] = @sepPos[i]
end
end
return
end
# 次の分割場所を設定する
(pos + 1).upto( @value.length - @separator + num ) do |i|
separate( i, num )
end
end
def main
# 最初の分割場所を設定して再帰を呼び出す
(@value.length - @separator).times do |i|
separate( i, 0 )
end
# 保存された分割場所を表示する
0.upto( @separator ) do |i|
start = ( i == 0 ) ? @value.length : @bestSepPos[i - 1]
last = ( i == @separator ) ? @value.length : @bestSepPos[i]
start.upto( last - 1) do |j|
printf "#{@value[j]} "
end
if last != @value.length
printf "| "
end
end
end
end
sep = SeparatorBackTruck.new
sep.main
class SeparatorActivePlan
class Cell
attr_accessor :sol, :num
def initialize
@sol = nil
@num = nil
end
end
def initialize
@array = [15, 3, 7, 6, 10, 4, 13, 2, 3, 6]
@separator = 3
end
def main
solutions = Array.new(@array.length)
solutions.each_index do |i|
solutions[i] = Array.new( @separator + 1 )
end
# 配列の後ろの方から順に埋めていく
i = @array.length - 1
while i >= 0
0.upto( @separator + 1 ) do |j|
solutions[i][j] = Cell.new
solutions[i][j].num = 0
solutions[i][j].sol = 0
sum = 0
i.upto( @array.length - 1) do |s|
sum += @array[s]
if j == 0 ||
i == @array.length - 1 ||
solutions[i][j].num == 0 ||
(s != @array.length - 1 &&
solutions[i][j].sol > [sum, solutions[s + 1][j - 1].sol].max )
if j == 0 || i == @array.length - 1
solutions[i][j].sol = sum
else
solutions[i][j].sol = [sum, solutions[s + 1][j - 1].sol].max
end
solutions[i][j].num = s - i + 1
end
end
end
i -= 1
end
# デバッグ用にテーブルを表示
0.upto( @separator ) do |j|
@array.length.times do |i|
printf "#{solutions[i][j].num},#{solutions[i][j].sol} "
end
puts
end
# 結果表示
printf "MAX : #{solutions[0][@separator].sol}¥n"
printf "Sepalate:"
i = 0
j = @separator
while j >= 0 && i != @array.length
printf "[#{solutions[i][j].num}]"
i += solutions[i][j].num
j -= 1
end
end
end
sep = SeparatorActivePlan.new
sep.main