class KnapsackDP
attr_accessor :s,:n,:mv
def initialize(s,n)
@s = s
@n = n
initMaxValue()
@bestValue = search(s,n)
@bestDiff = (n - @bestValue).abs
@upperValue = n + @bestDiff
@lowerValue = n - @bestDiff
puts "init value=" + @bestValue.to_s + " diff=" + @bestDiff.to_s
end
def encodeItemList(s,n)
return (n.to_s(2)).reverse.each_char.with_index.select {|c,i| c=="1"}.map{|c,i| s[i]}
end
def encodeValue(s,n)
return encodeItemList(s,n).inject(:+)
end
def search (s,n)
s.sort!
if n < (minValue = s.min)
@bestTrace = [minValue]
return minValue
elsif n > (maxValue = s.inject(:+))
@bestTrace = s
return maxValue
else
left=1
right=(2** (s.length())) -1
while left < right do
mid = (left + right) / 2
curValue = encodeValue(s,mid)
if n < curValue
right = mid - 1
elsif curValue < n
left = mid + 1
else
@bestTrace = encodeItemList(s,mid)
return curValue
end
end
curValue1 = encodeValue(s,left)
curValue2 = encodeValue(s,left+1)
if (n - curValue1).abs < (curValue2 - n).abs
@bestTrace = encodeItemList(s,left)
return curValue1
else
@bestTrace = encodeItemList(s,left+1)
return curValue2
end
end
end
def initMaxValue()
@mv = Array.new(@s.length){ Array.new(@s.length, 0)}
@mv.last[@s.length() - 1] = @s.last
(@s.length() -2).downto(0) do |i|
@mv[i][@s.length() - 1] = @s[i] + @s.last
(@s.length() - 2).downto(i+1) do |j|
@mv[i][j] = @s[i] + @mv[j][j+1]
end
@mv[i][i] = @s[i]
end
# @mv.each {|d| p d}
end
def evalAcc(curAcc,trace)
curDiff = (n-curAcc).abs
# p ["evalAcc",curAcc,trace]
if curDiff < @bestDiff
@bestValue = curAcc
@bestDiff = curDiff
@upperValue = n + @bestDiff
@lowerValue = n - @bestDiff
@bestTrace = trace
end
end
def findNear(i,acc,trace)
# p ["findNear",@s.length,i,acc,trace]
if (i >= @s.length() -1)
evalAcc(acc,trace) ## 止めた場合
# p "exit at #1"
return
elsif (acc ) > @upperValue ## 既に上限を超えた場合
# p "exit at #2 acc=" + acc.to_s + " > " + @upperValue.to_s
return
else
findNear(i+2,(acc),trace) ## s[i]を足さないで、後続の数列を加算
(i+1).upto(@s.length() -1) do |j|
if ((acc + @mv[i][j]) >= @lowerValue) ## まだ下限値を超える見込みの在る値
# p "findNear i=" + i.to_s + " j=" + j.to_s + " " + (trace + [s[j]]).to_s
findNear(j+1,(acc + @s[j]),trace + [s[j]]) ## s[i]とs[j]を足して、後続の数列を加算
else
# p "break at #4 acc=" + acc.to_s + " " + "@mv[" + i.to_s + "][" + j.to_s + "]=" + @mv[i][j].to_s + " < " + @lowerValue.to_s
break
end
end
end
end
def findValue()
findNear(1,0,[])
findNear(0,@s[0],[s[0]])
puts "nearest Value =" + @bestValue.to_s() + " diff=" + @bestDiff.to_s()
p @bestTrace
p @bestTrace.inject(:+)
p @s
end
end
q1=KnapsackDP.new([17,19,23,29],42)
q1.findValue()
Y2xhc3MgS25hcHNhY2tEUAogIGF0dHJfYWNjZXNzb3IgOnMsOm4sOm12CiAgZGVmIGluaXRpYWxpemUocyxuKQogICAgQHMgPSBzCiAgICBAbiA9IG4KICAgIGluaXRNYXhWYWx1ZSgpCiAgICBAYmVzdFZhbHVlID0gc2VhcmNoKHMsbikKICAgIEBiZXN0RGlmZiA9IChuIC0gQGJlc3RWYWx1ZSkuYWJzCiAgICBAdXBwZXJWYWx1ZSA9IG4gKyBAYmVzdERpZmYKICAgIEBsb3dlclZhbHVlID0gbiAtIEBiZXN0RGlmZgogICAgcHV0cyAiaW5pdCB2YWx1ZT0iICsgQGJlc3RWYWx1ZS50b19zICsgIiBkaWZmPSIgKyBAYmVzdERpZmYudG9fcwogIGVuZAogIGRlZiBlbmNvZGVJdGVtTGlzdChzLG4pCiAgICByZXR1cm4gKG4udG9fcygyKSkucmV2ZXJzZS5lYWNoX2NoYXIud2l0aF9pbmRleC5zZWxlY3Qge3xjLGl8IGM9PSIxIn0ubWFwe3xjLGl8IHNbaV19CiAgZW5kCiAgZGVmIGVuY29kZVZhbHVlKHMsbikKICAgIHJldHVybiBlbmNvZGVJdGVtTGlzdChzLG4pLmluamVjdCg6KykKICBlbmQKIAogIGRlZiBzZWFyY2ggKHMsbikKICAgIHMuc29ydCEKICAgIGlmIG4gPCAobWluVmFsdWUgPSBzLm1pbikKICAgICAgIEBiZXN0VHJhY2UgPSBbbWluVmFsdWVdCiAgICAgICByZXR1cm4gbWluVmFsdWUKICAgIGVsc2lmIG4gPiAobWF4VmFsdWUgPSBzLmluamVjdCg6KykpCiAgICAgICBAYmVzdFRyYWNlID0gcwogICAgICAgcmV0dXJuIG1heFZhbHVlCiAgICBlbHNlCiAgICAgICAgbGVmdD0xCiAgICAgICAgcmlnaHQ9KDIqKiAocy5sZW5ndGgoKSkpIC0xCiAgICAgICAgd2hpbGUgbGVmdCA8IHJpZ2h0IGRvCiAgICAgICAgICBtaWQgPSAobGVmdCArIHJpZ2h0KSAvIDIKICAgICAgICAgIGN1clZhbHVlID0gZW5jb2RlVmFsdWUocyxtaWQpCiAgICAgICAgICBpZiBuIDwgY3VyVmFsdWUKICAgICAgICAgICAgcmlnaHQgPSBtaWQgLSAxCiAgICAgICAgICBlbHNpZiBjdXJWYWx1ZSA8IG4KICAgICAgICAgICAgbGVmdCA9IG1pZCArIDEKICAgICAgICAgIGVsc2UKICAgICAgICAgICAgQGJlc3RUcmFjZSA9IGVuY29kZUl0ZW1MaXN0KHMsbWlkKQogICAgICAgICAgICByZXR1cm4gY3VyVmFsdWUKICAgICAgICAgIGVuZAogICAgICAgIGVuZAogICAgICAgIGN1clZhbHVlMSA9IGVuY29kZVZhbHVlKHMsbGVmdCkKICAgICAgICBjdXJWYWx1ZTIgPSBlbmNvZGVWYWx1ZShzLGxlZnQrMSkKICAgICAgICBpZiAobiAtIGN1clZhbHVlMSkuYWJzIDwgKGN1clZhbHVlMiAtIG4pLmFicwogICAgICAgICAgQGJlc3RUcmFjZSA9IGVuY29kZUl0ZW1MaXN0KHMsbGVmdCkKICAgICAgICAgIHJldHVybiBjdXJWYWx1ZTEKICAgICAgICBlbHNlCiAgICAgICAgICBAYmVzdFRyYWNlID0gZW5jb2RlSXRlbUxpc3QocyxsZWZ0KzEpCiAgICAgICAgICByZXR1cm4gY3VyVmFsdWUyCiAgICAgICAgZW5kCiAgICBlbmQKICBlbmQKICBkZWYgaW5pdE1heFZhbHVlKCkKICAgICBAbXYgPSBBcnJheS5uZXcoQHMubGVuZ3RoKXsgQXJyYXkubmV3KEBzLmxlbmd0aCwgMCl9CiAgICAgQG12Lmxhc3RbQHMubGVuZ3RoKCkgLSAxXSA9IEBzLmxhc3QKICAgICAoQHMubGVuZ3RoKCkgLTIpLmRvd250bygwKSBkbyB8aXwKICAgICAgICBAbXZbaV1bQHMubGVuZ3RoKCkgLSAxXSA9IEBzW2ldICsgQHMubGFzdAogICAgICAgIChAcy5sZW5ndGgoKSAtIDIpLmRvd250byhpKzEpIGRvIHxqfAogICAgICAgICAgQG12W2ldW2pdID0gQHNbaV0gKyBAbXZbal1baisxXQogICAgICAgIGVuZAogICAgICAgIEBtdltpXVtpXSA9IEBzW2ldCiAgICAgZW5kCgkgICAjIEBtdi5lYWNoIHt8ZHwgcCBkfQogIGVuZAogIGRlZiBldmFsQWNjKGN1ckFjYyx0cmFjZSkKICAgIGN1ckRpZmYgPSAobi1jdXJBY2MpLmFicwogICAgIyBwIFsiZXZhbEFjYyIsY3VyQWNjLHRyYWNlXQogICAgaWYgY3VyRGlmZiA8IEBiZXN0RGlmZgogICAgICAgQGJlc3RWYWx1ZSA9IGN1ckFjYwogICAgICAgQGJlc3REaWZmID0gY3VyRGlmZgogICAgICAgQHVwcGVyVmFsdWUgPSBuICsgQGJlc3REaWZmCiAgICAgICBAbG93ZXJWYWx1ZSA9IG4gLSBAYmVzdERpZmYKICAgICAgIEBiZXN0VHJhY2UgPSB0cmFjZQogICAgZW5kCiAgZW5kCiAgZGVmIGZpbmROZWFyKGksYWNjLHRyYWNlKQogICAgIyBwIFsiZmluZE5lYXIiLEBzLmxlbmd0aCxpLGFjYyx0cmFjZV0KICAgIGlmIChpID49IEBzLmxlbmd0aCgpIC0xKQogICAgICAgZXZhbEFjYyhhY2MsdHJhY2UpICMjIOatouOCgeOBn+WgtOWQiAogICAgIyAgIHAgImV4aXQgYXQgIzEiCiAgICAgICByZXR1cm4KICAgIGVsc2lmIChhY2MgKSA+IEB1cHBlclZhbHVlICMjIOaXouOBq+S4iumZkOOCkui2heOBiOOBn+WgtOWQiAogICAgIyAgIHAgImV4aXQgYXQgIzIgYWNjPSIgKyBhY2MudG9fcyArICIgPiAiICsgQHVwcGVyVmFsdWUudG9fcwogICAgICAgcmV0dXJuCiAgICBlbHNlCiAgICAgICBmaW5kTmVhcihpKzIsKGFjYyksdHJhY2UpIAkJIyMgc1tpXeOCkui2s+OBleOBquOBhOOBp+OAgeW+jOe2muOBruaVsOWIl+OCkuWKoOeulwogICAgICAgKGkrMSkudXB0byhAcy5sZW5ndGgoKSAtMSkgZG8gfGp8CiAgICAgICAgICAgICBpZiAoKGFjYyArIEBtdltpXVtqXSkgPj0gQGxvd2VyVmFsdWUpICAjIyDjgb7jgaDkuIvpmZDlgKTjgpLotoXjgYjjgovopovovrzjgb/jga7lnKjjgovlgKQKCSAgICAgICAgICAgICAjIHAgImZpbmROZWFyIGk9IiArIGkudG9fcyArICIgaj0iICsgai50b19zICsgIiAiICsgKHRyYWNlICsgW3Nbal1dKS50b19zCiAgICAgICAgICAgICAgIGZpbmROZWFyKGorMSwoYWNjICsgQHNbal0pLHRyYWNlICsgW3Nbal1dKSAjIyBzW2ld44Goc1tqXeOCkui2s+OBl+OBpuOAgeW+jOe2muOBruaVsOWIl+OCkuWKoOeulwogICAgICAgICAgICAgZWxzZSAKICAgICMgICAgICAgICAgIHAgImJyZWFrIGF0ICM0IGFjYz0iICsgYWNjLnRvX3MgKyAiICIgKyAiQG12WyIgKyBpLnRvX3MgKyAiXVsiICsgai50b19zICsgIl09IiArIEBtdltpXVtqXS50b19zICsgIiA8ICIgKyBAbG93ZXJWYWx1ZS50b19zCiAgICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICAgZW5kCiAgICAgICBlbmQKICAgIGVuZAogIGVuZAogIGRlZiBmaW5kVmFsdWUoKQogICAgIGZpbmROZWFyKDEsMCxbXSkKICAgICBmaW5kTmVhcigwLEBzWzBdLFtzWzBdXSkKICAgICBwdXRzICJuZWFyZXN0IFZhbHVlID0iICsgQGJlc3RWYWx1ZS50b19zKCkgKyAiIGRpZmY9IiArIEBiZXN0RGlmZi50b19zKCkKICAgICBwIEBiZXN0VHJhY2UKICAgICBwIEBiZXN0VHJhY2UuaW5qZWN0KDorKQogCiAgICAgcCBAcwogIGVuZAplbmQKcTE9S25hcHNhY2tEUC5uZXcoWzE3LDE5LDIzLDI5XSw0MikKcTEuZmluZFZhbHVlKCk=