Knapsack problem/Bounded: Difference between revisions
m
→{{header|Wren}}: Minor tidy
m (→{{header|Wren}}: Minor tidy) |
|||
(44 intermediate revisions by 23 users not shown) | |||
Line 11:
This is the list:
:::::{| style="text-align: left; width:
|+ Table of potential knapsack items
|- style="background-color: rgb(255, 204, 255);"
Line 78:
* [[Knapsack problem/0-1]]
<br><br>
=={{header|11l}}==
{{trans|Python}}
<syntaxhighlight lang="11l">V items = [
‘sandwich’ = (50, 60, 2),
‘map’ = (9, 150, 1),
‘compass’ = (13, 35, 1),
‘water’ = (153, 200, 3),
‘glucose’ = (15, 60, 2),
‘tin’ = (68, 45, 3),
‘banana’ = (27, 60, 3),
‘apple’ = (39, 40, 3),
‘cheese’ = (23, 30, 1),
‘beer’ = (52, 10, 3),
‘suntan cream’ = (11, 70, 1),
‘camera’ = (32, 30, 1),
‘t-shirt’ = (24, 15, 2),
‘trousers’ = (48, 10, 2),
‘umbrella’ = (73, 40, 1),
‘w-trousers’ = (42, 70, 1),
‘w-overcoat’ = (43, 75, 1),
‘note-case’ = (22, 80, 1),
‘sunglasses’ = (7, 20, 1),
‘towel’ = (18, 12, 2),
‘socks’ = (4, 50, 1),
‘book’ = (30, 10, 2)
]
V item_keys = items.keys()
[(Int, Int) = (Int, [(Int, String)])] cache
F choose_item(weight, idx)
[(Int, String)] best_list
I idx < 0
R (0, best_list)
V k = (weight, idx)
V? c = :cache.find(k)
I c != N
R c
V name = :item_keys[idx]
V (w, v, qty) = :items[name]
V best_v = 0
L(i) 0..qty
V wlim = weight - i * w
I wlim < 0
L.break
V (val, taken) = choose_item(wlim, idx - 1)
I val + i * v > best_v
best_v = val + i * v
best_list = copy(taken)
best_list.append((i, name))
:cache[k] = (best_v, best_list)
R (best_v, best_list)
V (v, lst) = choose_item(400, items.len - 1)
V w = 0
L(cnt, name) lst
I cnt > 0
print(cnt‘ ’name)
w += items[name][0] * cnt
print(‘Total weight: ’w‘ Value: ’v)</syntaxhighlight>
{{out}}
<pre>
3 banana
1 cheese
1 compass
2 glucose
1 map
1 note-case
1 socks
1 sunglasses
1 suntan cream
1 w-overcoat
1 water
Total weight: 396 Value: 1010
</pre>
=={{header|AutoHotkey}}==
iterative dynamic programming solution
<
,camera,tshirt,trousers,umbrella,waterproof trousers,waterproof overclothes,notecase
,sunglasses,towel,socks,book
Line 117 ⟶ 198:
}
MsgBox % "Value = " m%N%_%W% "`nWeight = " s "`n`n" t</
=={{header|Bracmat}}==
<
( things
= (map.9.150.1)
Line 193 ⟶ 274:
);
!knapsack;</
{{out}}
<pre> 1010
Line 210 ⟶ 291:
=={{header|C}}==
<
#include <stdlib.h>
Line 294 ⟶ 375:
return 0;
}
</syntaxhighlight>
{{output}}
Line 309 ⟶ 390:
socks 1 4 50
count, weight, value: 14 396 1010</pre>
=={{header|C sharp|C#}}==
Similar to Knapsack/0-1.
<syntaxhighlight lang="csharp">using System; // 4790@3.6
class program
{
static void Main()
{
knapSack(40);
var sw = System.Diagnostics.Stopwatch.StartNew();
Console.Write(knapSack(400) + "\n" + sw.Elapsed); // 51 µs
Console.Read();
}
static string knapSack(uint w1)
{
init(); change();
uint n = (uint)w.Length; var K = new uint[n + 1, w1 + 1];
for (uint vi, wi, w0, x, i = 0; i < n; i++)
for (vi = v[i], wi = w[i], w0 = 1; w0 <= w1; w0++)
{
x = K[i, w0];
if (wi <= w0) x = max(vi + K[i, w0 - wi], x);
K[i + 1, w0] = x;
}
string str = "";
for (uint v1 = K[n, w1]; v1 > 0; n--)
if (v1 != K[n - 1, w1])
{
v1 -= v[n - 1]; w1 -= w[n - 1]; str += items[n - 1] + "\n";
}
return str;
}
static uint max(uint a, uint b) { return a > b ? a : b; }
static byte[] w, v; static string[] items;
static byte[] p = { 1, 1, 2, 2, 2, 3, 3, 3, 1, 3, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2 };
static void init()
{
w = new byte[] { 9, 13, 153, 50, 15, 68, 27, 39, 23, 52, 11,
32, 24, 48, 73, 42, 43, 22, 7, 18, 4, 30 };
v = new byte[] { 150, 35, 200, 60, 60, 45, 60, 40, 30, 10, 70,
30, 15, 10, 40, 70, 75, 80, 20, 12, 50, 10 };
items = new string[] {"map","compass","water","sandwich","glucose","tin",
"banana","apple","cheese","beer","suntan cream",
"camera","T-shirt","trousers","umbrella",
"waterproof trousers","waterproof overclothes",
"note-case","sunglasses","towel","socks","book"};
}
static void change()
{
int n = w.Length, s = 0, i, j, k; byte xi;
for (i = 0; i < n; i++) s += p[i];
{
byte[] x = new byte[s];
for (k = i = 0; i < n; i++)
for (xi = w[i], j = p[i]; j > 0; j--) x[k++] = xi;
w = x;
}
{
byte[] x = new byte[s];
for (k = i = 0; i < n; i++)
for (xi = v[i], j = p[i]; j > 0; j--) x[k++] = xi;
v = x;
}
string[] pItems = new string[s]; string itemI;
for (k = i = 0; i < n; i++)
for (itemI = items[i], j = p[i]; j > 0; j--) pItems[k++] = itemI;
items = pItems;
}
}</syntaxhighlight>
=={{header|C++}}==
C++ DP solution. Initially taken from C but than fixed and refactored.<br>
Remark: The above comment implies there is a bug in the C code, but refers to a much older and very different version [[User:Petelomax|Pete Lomax]] ([[User talk:Petelomax|talk]]) 19:28, 20 March 2017 (UTC)
<
#include <vector>
#include <algorithm>
Line 548 ⟶ 706:
cout << "Weight: " << solution.w << " Value: " << solution.v << endl;
return 0;
}</
=={{header|Clojure}}==
We convert the problem to a Knapsack-0/1 problem by replacing (n-max item) vith n-max identical occurences of 1 item.
Adapted Knapsack-0/1 problem solution from [https://www.rosettacode.org/wiki/Knapsack_problem/0-1#Clojure]
<
(:gen-class))
Line 613 ⟶ 771:
(println "Total value:" value)
(println "Total weight:" (reduce + (map (comp :weight items) indexes))))
</syntaxhighlight>
{{Output}}
<pre>
Line 631 ⟶ 789:
Total weight: 396
</pre>
=={{header|Common Lisp}}==
<
(defmacro mm-set (p v) `(if ,p ,p (setf ,p ,v)))
Line 665 ⟶ 824:
(T-shirt 24 15 2) (trousers 48 10 2) (umbrella 73 40 1)
(trousers 42 70 1) (overclothes 43 75 1) (notecase 22 80 1)
(glasses 7 20 1) (towel 18 12 2) (socks 4 50 1) (book 30 10 2))))</
=={{header|Crystal}}==
==== Branch and Bound solution ====
<syntaxhighlight lang="ruby">record Item, name : String, weight : Int32, value : Int32, count : Int32
record Selection, mask : Array(Int32), cur_index : Int32, total_value : Int32
class Knapsack
@threshold_value = 0
@threshold_choice : Selection?
getter checked_nodes = 0
def knapsack_step(taken, items, remaining_weight)
if taken.total_value > @threshold_value
@threshold_value = taken.total_value
@threshold_choice = taken
end
candidate_index = items.index(taken.cur_index) { |item| item.weight <= remaining_weight }
return nil unless candidate_index
@checked_nodes += 1
candidate = items[candidate_index]
# candidate is a best of available items, so if we fill remaining value with
# and still don't reach the threshold, the branch is wrong
return nil if taken.total_value + 1.0 * candidate.value / candidate.weight * remaining_weight < @threshold_value
# now recursively check all variants (from taking maximum count to taking nothing)
max_count = {candidate.count, remaining_weight // candidate.weight}.min
(0..max_count).reverse_each do |n|
mask = taken.mask.clone
mask[candidate_index] = n
knapsack_step Selection.new(mask, candidate_index + 1, taken.total_value + n*candidate.value), items, remaining_weight - n*candidate.weight
end
end
def select(items, max_weight)
@checked_variants = 0
# sort by descending relative value
list = items.sort_by { |item| -1.0 * item.value / item.weight }
nothing = Selection.new(Array(Int32).new(items.size, 0), 0, 0)
@threshold_value = 0
@threshold_choice = nothing
knapsack_step(nothing, list, max_weight)
selected = @threshold_choice.not_nil!
result = Hash(Item, Int32).new(0)
selected.mask.each_with_index { |v, i| result[list[i]] = v if v > 0 }
result
end
end
possible = [
Item.new("map", 9, 150, 1),
Item.new("compass", 13, 35, 1),
Item.new("water", 153, 200, 2),
Item.new("sandwich", 50, 60, 2),
Item.new("glucose", 15, 60, 2),
Item.new("tin", 68, 45, 3),
Item.new("banana", 27, 60, 3),
Item.new("apple", 39, 40, 3),
Item.new("cheese", 23, 30, 1),
Item.new("beer", 52, 10, 3),
Item.new("suntan cream", 11, 70, 1),
Item.new("camera", 32, 30, 1),
Item.new("T-shirt", 24, 15, 2),
Item.new("trousers", 48, 10, 2),
Item.new("umbrella", 73, 40, 1),
Item.new("waterproof trousers", 42, 70, 1),
Item.new("waterproof overclothes", 43, 75, 1),
Item.new("note-case", 22, 80, 1),
Item.new("sunglasses", 7, 20, 1),
Item.new("towel", 18, 12, 2),
Item.new("socks", 4, 50, 1),
Item.new("book", 30, 10, 2),
]
solver = Knapsack.new
used = solver.select(possible, 400)
puts "optimal choice: #{used.map { |item, count| count == 1 ? item.name : "#{count}x #{item.name}" }.join(", ")}"
puts "total weight #{used.sum { |item, count| item.weight*count }}"
puts "total value #{used.sum { |item, count| item.value*count }}"
puts "checked nodes: #{solver.checked_nodes}"</syntaxhighlight>
{{out}}
<pre>optimal choice: map, socks, suntan cream, 2x glucose, note-case, sunglasses, compass, 3x banana, waterproof overclothes, water, cheese
total weight 396
total value 1010
checked nodes: 1185
</pre>
==== Dynamic programming solution ====
{{trans|Ruby}}
<syntaxhighlight lang="ruby"># Item struct to represent each item in the problem
record Item, name : String, weight : Int32, value : Int32, count : Int32
def choose_item(items, weight, id, cache)
return 0, ([] of Int32) if id < 0
k = {weight, id}
cache = cache || {} of Tuple(Int32, Int32) => Tuple(Int32, Array(Int32))
return cache[k] if cache[k]?
value = items[id].value
best_v = 0
best_list = [] of Int32
(items[id].count + 1).times do |i|
wlim = weight - i * items[id].weight
break if wlim < 0
val, taken = choose_item(items, wlim, id - 1, cache)
if val + i * value > best_v
best_v = val + i * value
best_list = taken + [i]
end
end
cache[k] = {best_v, best_list}
return {best_v, best_list}
end
items = [
Item.new("map", 9, 150, 1),
Item.new("compass", 13, 35, 1),
Item.new("water", 153, 200, 2),
Item.new("sandwich", 50, 60, 2),
Item.new("glucose", 15, 60, 2),
Item.new("tin", 68, 45, 3),
Item.new("banana", 27, 60, 3),
Item.new("apple", 39, 40, 3),
Item.new("cheese", 23, 30, 1),
Item.new("beer", 52, 10, 3),
Item.new("suntan cream", 11, 70, 1),
Item.new("camera", 32, 30, 1),
Item.new("T-shirt", 24, 15, 2),
Item.new("trousers", 48, 10, 2),
Item.new("umbrella", 73, 40, 1),
Item.new("waterproof trousers", 42, 70, 1),
Item.new("waterproof overclothes", 43, 75, 1),
Item.new("note-case", 22, 80, 1),
Item.new("sunglasses", 7, 20, 1),
Item.new("towel", 18, 12, 2),
Item.new("socks", 4, 50, 1),
Item.new("book", 30, 10, 2),
]
val, list = choose_item(items, 400, items.size - 1, nil)
w = 0
list.each_with_index do |cnt, i|
if cnt > 0
print "#{cnt} #{items[i].name}\n"
w += items[i].weight * cnt
end
end
p "Total weight: #{w}, Value: #{val}"</syntaxhighlight>
=={{header|D}}==
{{trans|Python}}
Solution with memoization.
<
immutable struct Item {
Line 726 ⟶ 1,034:
writeln("Total weight: ", w, " Value: ", v_lst[0]);
}</
{{out}}
<pre>1 map
Line 743 ⟶ 1,051:
=={{header|EchoLisp}}==
We convert the problem to a Knapsack-0/1 problem by replacing (n-max item) vith n-max identical occurences of 1 item.
<
(lib 'struct)
(lib 'sql)
Line 799 ⟶ 1,107:
(name i))))
</syntaxhighlight>
{{out}}
<
(define goodies
'((map 9 150 1) (compass 13 35 1)(water 153 200 3)
Line 821 ⟶ 1,129:
(length (hash-keys H))
→ 10827 ;; # of entries in cache
</syntaxhighlight>
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">#define PesoMax 400
#define items 22
#define Tabu Chr(9)
Type Knapsack
articulo As String*22
peso As Integer
valor As Integer
pieza As Integer
End Type
Dim item(1 To 22) As Knapsack => { _
("map ", 9, 150, 0), ("compass ", 13, 35, 0), _
("water ", 153, 200, 0), ("sandwich ", 50, 160, 0), _
("glucose ", 15, 60, 0), ("tin ", 68, 45, 0), _
("banana ", 27, 60, 0), ("apple ", 39, 40, 0), _
("cheese ", 23, 30, 0), ("beer ", 52, 10, 0), _
("suntan cream ", 11, 70, 0), ("camera ", 32, 30, 0), _
("T-shirt ", 24, 15, 0), ("trousers ", 48, 10, 0), _
("umbrella ", 73, 40, 0), ("waterproof trousers ", 42, 70, 0), _
("waterproof overclothes", 43, 75, 0), ("note-case ", 22, 80, 0), _
("sunglasses ", 7, 20, 0), ("towel ", 18, 12, 0), _
("socks ", 4, 50, 0), ("book ", 30, 10, 0)}
Dim As Integer i, tot = 0, TValor = 0
For i =1 To Ubound(item)
tot += item(i).peso
Next i
Dim As Integer TPeso = tot-PesoMax
Dim As String pr = ""
Dim As Integer c = 0, v, w, k
Do
v = 1e9 : w = 0 : k = 0
For i = 1 To items
If item(i).pieza = 0 Then
w = 1000 * item(i).valor / item(i).peso
If w < v Then v = w : k = i
End If
Next i
If k Then
TPeso -= item(k).peso
item(k).pieza = 1
If TPeso <= 0 Then Exit Do
End If
c += 1
Loop Until c>= items
Print "Knapsack contents: "
For i = 1 To items
If item(i).pieza = 0 Then
Print item(i).articulo & Tabu & item(i).peso & Tabu & item(i).valor
TValor += item(i).valor
End If
Next i
Print !"\nTotal value: "; TValor
Print "Total weight: "; PesoMax + TPeso
Sleep</syntaxhighlight>
{{out}}
<pre>Knapsack contents:
map 9 150
compass 13 35
water 153 200
sandwich 50 160
glucose 15 60
banana 27 60
suntan cream 11 70
waterproof trousers 42 70
waterproof overclothes 43 75
note-case 22 80
sunglasses 7 20
socks 4 50
Total value: 1030
Total weight: 396</pre>
=={{header|Go}}==
Solution with caching.
<
import "fmt"
Line 923 ⟶ 1,311:
}
fmt.Printf("Value: %d; weight: %d\n", v, w)
}</
(A simple test and benchmark used while making changes to make sure performance wasn't sacrificed is available at [[/Go_test]].)
{{out}}
Line 942 ⟶ 1,330:
=={{header|Groovy}}==
Solution: dynamic programming
<
def totalValue = { list -> list.collect{ it.item.value * it.count }.sum() }
Line 959 ⟶ 1,347:
}
m[n][400]
}</
Test:
<
[name:"map", weight: 9, value:150, pieces:1],
[name:"compass", weight: 13, value: 35, pieces:1],
Line 996 ⟶ 1,384:
printf (' item: %-22s weight:%4d value:%4d count:%2d\n',
it.item.name, it.item.weight, it.item.value, it.count)
}</
{{out}}
<pre>Elapsed Time: 0.603 s
Line 1,015 ⟶ 1,403:
=={{header|Haskell}}==
Directly lifted from 1-0 problem:
<
("glucose",15,60,2), ("tin",68,45,3), ("banana",27,60,3), ("apple",39,40,3),
("cheese",23,30,1), ("beer",52,10,3), ("cream",11,70,1), ("camera",32,30,1),
Line 1,029 ⟶ 1,417:
new = map (\(val,itms)->(val + v * i, (name,i):itms)) old
main = print $ (knapsack inv) !! 400</
{{out}}
Line 1,036 ⟶ 1,424:
</pre>
The above uses merging lists for cache. It's faster, and maybe easier to understand when some constant-time lookup structure is used for cache (same output):
<
-- snipped the item list; use the one from above
Line 1,046 ⟶ 1,434:
prepend (x,n) (y,s) = (x+y,n:s)
main = do print $ knapsack inv 400</
=={{header|J}}==
Brute force solution:
<
'map'; 9 150 1
'compass'; 13 35 1
Line 1,099 ⟶ 1,487:
bestCombo''
978832641</
Interpretation of answer:
<
1 1 1 0 2 0 3 0 1 0 1 0 0 0 0 0 1 1 1 0 1 0
(0<decode 978832641) # (":,.decode 978832641),.' ',.names
Line 1,118 ⟶ 1,506:
396
values +/ .* decode 978832641
1010</
Dynamic programming solution (faster):
<
m=. 0$~1+400,+/pieces NB. maximum value cache
b=. m NB. best choice cache
Line 1,146 ⟶ 1,534:
dyn''
1 1 1 0 2 0 3 0 1 0 1 0 0 0 0 0 1 1 1 0 1 0</
Note: the brute force approach would return multiple "best answers" if more than one combination of choices would satisfy the "best" constraint. The dynamic approach arbitrarily picks one of those choices. That said, with this particular choice of item weights and values, this is an irrelevant distinction.
=={{header|Java}}==
General dynamic solution after [[wp:Knapsack_problem#0-1_knapsack_problem|wikipedia]]. The solution extends the method of [[Knapsack problem/0-1#Java ]].
<
import hu.pj.alg.BoundedKnapsack;
Line 1,233 ⟶ 1,621:
new BoundedKnapsackForTourists();
}
} // class</
<
import hu.pj.obj.Item;
Line 1,296 ⟶ 1,684:
setInitialStateForCalculation();
}
} // class</
<
import hu.pj.obj.Item;
Line 1,448 ⟶ 1,836:
solutionWeight = 0;
}
} // class</
<
public class Item {
Line 1,517 ⟶ 1,905:
public int getInKnapsack() {return inKnapsack;}
public int getBounding() {return bounding;}
} // class</
{{out}}
<pre>
Line 1,540 ⟶ 1,928:
=={{header|JavaScript}}==
Based on the (dynamic) J implementation. Expressed as an htm page:
<
<script type="text/javascript">
Line 1,618 ⟶ 2,006:
}
findBestPack();
</script></
This will generate (translating html to mediawiki markup):
{|
Line 1,683 ⟶ 2,071:
Total weight: 396<br>
Total value: 1010
=={{header|jq}}==
'''Adapted from [[#Wren|Wren]]'''
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
<syntaxhighlight lang="jq"># Item {name, weight, value, count}
def Item($name; $weight; $value; $count): {$name, $weight, $value, $count};
def items: [
Item("map"; 9; 150; 1),
Item("compass"; 13; 35; 1),
Item("water"; 153; 200; 2),
Item("sandwich"; 50; 60; 2),
Item("glucose"; 15; 60; 2),
Item("tin"; 68; 45; 3),
Item("banana"; 27; 60; 3),
Item("apple"; 39; 40; 3),
Item("cheese"; 23; 30; 1),
Item("beer"; 52; 10; 3),
Item("suntan cream"; 11; 70; 1),
Item("camera"; 32; 30; 1),
Item("T-shirt"; 24; 15; 2),
Item("trousers"; 48; 10; 2),
Item("umbrella"; 73; 40; 1),
Item("waterproof trousers"; 42; 70; 1),
Item("waterproof overclothes"; 43; 75; 1),
Item("note-case"; 22; 80; 1),
Item("sunglasses"; 7; 20; 1),
Item("towel"; 18; 12; 2),
Item("socks"; 4; 50; 1),
Item("book"; 30; 10; 2)
];
def knapsack($w):
def list($init): [range(0; .) | $init];
(items|length) as $n
| {m: ($n+1 | list( $w + 1 | list(0) )) }
| reduce range(1; $n+1) as $i (.;
reduce range (0; $w + 1) as $j (.;
.m[$i][$j] = .m[$i-1][$j]
| label $out
| foreach (range(1; 1 + ((items[$i - 1].count))), null) as $k (.stop = false;
if $k == null then .
elif ($k * items[$i - 1].weight > $j) then .stop = true
else (.m[$i - 1][$j - ($k * items[$i - 1].weight)] + $k * items[$i - 1].value) as $v
| if $v > .m[$i][$j] then .m[$i][$j] = $v else . end
end;
if .stop or ($k == null) then ., break $out else empty end)
) )
| .s = ($n|list(0))
| .j = $w
| reduce range($n; 0; -1) as $i (.;
.m[$i][.j] as $v
| .k = 0
| until ($v == .m[$i - 1][.j] + .k * items[$i - 1].value;
.s[$i - 1] += 1
| .j = .j - items[$i - 1].weight
| .k += 1 ) )
| .s;
def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .;
def task(maxWeight):
def f(a;b;c;d): "\(a|lpad(22)) \(b|lpad(6)) \(c|lpad(6)) \(d|lpad(6))";
def f: . as [$a,$b,$c,$d] | f($a;$b;$c;$d);
(items|length) as $n
| knapsack(maxWeight) as $s
| f("Item Chosen"; "Weight";"Value";"Number"),
"---------------------- ------ ----- ------",
({ itemCount:0,
sumWeight:0,
sumValue :0,
sumNumber:0 }
| reduce range(0; $n) as $i (.;
if ($s[$i] != 0)
then .itemCount += 1
| .name = items[$i].name
| .number = $s[$i]
| .weight = items[$i].weight * .number
| .value = items[$i].value * .number
| .sumNumber += .number
| .sumWeight += .weight
| .sumValue += .value
| .emit += [[.name, .weight, .value, .number]]
else .
end )
| (.emit[] | f),
"---------------------- ------ ----- ------",
f("Items chosen \(.itemCount|lpad(4))"; .sumWeight; .sumValue; .sumNumber) );
task(400)
</syntaxhighlight>
{{out}}
<pre>
Item Chosen Weight Value Number
---------------------- ------ ----- ------
map 9 150 1
compass 13 35 1
water 153 200 1
glucose 30 120 2
banana 81 180 3
cheese 23 30 1
suntan cream 11 70 1
waterproof overclothes 43 75 1
note-case 22 80 1
sunglasses 7 20 1
socks 4 50 1
---------------------- ------ ----- ------
Items chosen 11 396 1010 14
</pre>
=={{header|Julia}}==
{{works with|Julia|0.6}}
The solution uses Julia's [https://github.com/JuliaOpt/MathProgBase.jl MathProgBase]. Most of the work is done with this package's <code>mixintprog</code> function.
'''Type and Function''':
<syntaxhighlight lang="julia">using MathProgBase, Cbc
item::
weight::T
value::T
quant::T
end
Base.show(io::IO, kdps::KPDSupply) = print(io, kdps.quant, " ", kdps.item, " ($(kdps.weight) kg, $(kdps.value) €)")
function solve
w = getfield.(gear, :weight)
sol = mixintprog(-v, w', '<', capacity, :Int, 0, q, CbcSolver())
sol.status ==
if all(q .== 1) # simpler case
return gear[sol.sol
else
pack =
s =
for (i, g) in enumerate(gear)
iszero(s[i])
push!(pack, KPDSupply(g.item, g.weight, g.value, s[i]))
end
return pack
end
end</syntaxhighlight>
'''Main''':
<syntaxhighlight lang="julia">gear = [KPDSupply("map", 9, 150, 1),
KPDSupply("compass", 13, 35, 1),
KPDSupply("water", 153, 200, 2),
Line 1,745 ⟶ 2,246:
pack = solve(gear, 400)
println("The hiker should pack: \n - ", join(pack, "\n - "))
println("\nPacked weight: ", sum(getfield.(pack, :weight)), " kg")
println("Packed value: ", sum(getfield.(pack, :value)), " €")</syntaxhighlight>
{{out}}
- 1 map (9 kg, 150 €)
- 1 compass (13 kg, 35 €)
- 1 water (153 kg, 200 €)
- 2 glucose (15 kg, 60 €)
- 3 banana (27 kg, 60 €)
- 1 cheese (23 kg, 30 €)
- 1 suntan cream (11 kg, 70 €)
- 1 waterproof overclothes (43 kg, 75 €)
- 1 note-case (22 kg, 80 €)
- 1 sunglasses (7 kg, 20 €)
- 1 socks (4 kg, 50 €)
Packed weight: 327 kg
Packed value: 830 €</pre>
=={{header|Kotlin}}==
{{trans|C}}
<syntaxhighlight lang="scala">// version 1.1.2
data class Item(val name: String, val weight: Int, val value: Int, val count: Int)
val items = listOf(
Item("map", 9, 150, 1),
Item("compass", 13, 35, 1),
Item("water", 153, 200, 2),
Item("sandwich", 50, 60, 2),
Item("glucose", 15, 60, 2),
Item("tin", 68, 45, 3),
Item("banana", 27, 60, 3),
Item("apple", 39, 40, 3),
Item("cheese", 23, 30, 1),
Item("beer", 52, 10, 3),
Item("suntan cream", 11, 70, 1),
Item("camera", 32, 30, 1),
Item("T-shirt", 24, 15, 2),
Item("trousers", 48, 10, 2),
Item("umbrella", 73, 40, 1),
Item("waterproof trousers", 42, 70, 1),
Item("waterproof overclothes", 43, 75, 1),
Item("note-case", 22, 80, 1),
Item("sunglasses", 7, 20, 1),
Item("towel", 18, 12, 2),
Item("socks", 4, 50, 1),
Item("book", 30, 10, 2)
)
val n = items.size
const val MAX_WEIGHT = 400
fun knapsack(w: Int): IntArray {
val m = Array(n + 1) { IntArray(w + 1) }
for (i in 1..n) {
for (j in 0..w) {
m[i][j] = m[i - 1][j]
for (k in 1..items[i - 1].count) {
if (k * items[i - 1].weight > j) break
val v = m[i - 1][j - k * items[i - 1].weight] + k * items[i - 1].value
if (v > m[i][j]) m[i][j] = v
}
}
}
val s = IntArray(n)
var j = w
for (i in n downTo 1) {
val v = m[i][j]
var k = 0
while (v != m[i - 1][j] + k * items[i - 1].value) {
s[i - 1]++
j -= items[i - 1].weight
k++
}
}
return s
}
fun main(args: Array<String>) {
val s = knapsack(MAX_WEIGHT)
println("Item Chosen Weight Value Number")
println("--------------------- ------ ----- ------")
var itemCount = 0
var sumWeight = 0
var sumValue = 0
var sumNumber = 0
for (i in 0 until n) {
if (s[i] == 0) continue
itemCount++
val name = items[i].name
val number = s[i]
val weight = items[i].weight * number
val value = items[i].value * number
sumNumber += number
sumWeight += weight
sumValue += value
println("${name.padEnd(22)} ${"%3d".format(weight)} ${"%4d".format(value)} ${"%2d".format(number)}")
}
println("--------------------- ------ ----- ------")
println("Items chosen $itemCount ${"%3d".format(sumWeight)} ${"%4d".format(sumValue)} ${"%2d".format(sumNumber)}")
}</syntaxhighlight>
{{out}}
<pre>
Item Chosen Weight Value Number
--------------------- ------ ----- ------
map 9 150 1
compass 13 35 1
water 153 200 1
glucose 30 120 2
banana 81 180 3
cheese 23 30 1
suntan cream 11 70 1
waterproof overclothes 43 75 1
note-case 22 80 1
sunglasses 7 20 1
socks 4 50 1
--------------------- ------ ----- ------
Items chosen 11 396 1010 14
</pre>
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<
LinearProgramming[-#[[;; , 3]], -{#[[;; , 2]]}, -{400},
{0, #[[4]]} & /@ #, Integers]} &@{{"map", 9, 150, 1},
Line 1,798 ⟶ 2,395:
{"towel", 18, 12, 2},
{"socks", 4, 50, 1},
{"book", 30, 10, 2}}</
{{Out}}
<pre>{{"map", 1}, {"compass", 1}, {"water", 1}, {"sandwich",
Line 1,809 ⟶ 2,406:
=={{header|Mathprog}}==
<
This model finds the integer optimal packing of a knapsack
Line 1,854 ⟶ 2,451:
;
end;</
The solution produced using glpk is here: [[Knapsack problem/Bounded/Mathprog]]
Line 1,861 ⟶ 2,458:
The constraints may be found here: [[:File:Knap_constraint.png]]
=={{header|MiniZinc}}==
<syntaxhighlight lang="minizinc">
%Solve Knapsack Problem Bounded. Nigel Galloway, Octoer 12th., 2020.
enum Items={map,compass,water,sandwich,glucose,tin,banana,apple,cheese,beer,suntan_cream,camera,t_shirt,trousers,umbrella,waterproof_trousers,waterproof_overclothes,note_case,sunglasses,towel,socks,book};
array[Items] of int: weight =[9,13,153,50,15,68,27,39,23,52,11,32,24,48,73,42,43,22,7,18,4,30];
array[Items] of int: value =[150,35,200,60,60,45,60,40,30,10,70,30,15,10,40,70,75,80,20,12,50,10];
array[Items] of int: quantity=[1,1,2,2,2,3,3,3,1,3,1,1,2,2,1,1,1,1,1,2,1,2];
array[Items] of var 0..max(quantity): take; constraint forall(n in Items)(take[n]<=quantity[n]);
int: maxWeight=400;
var int: wTaken=sum(n in Items)(weight[n]*take[n]);
var int: wValue=sum(n in Items)(value[n]*take[n]);
constraint wTaken <= maxWeight;
solve maximize wValue;
output[concat([let {string: g=show(take[n])} in "Take "++(if g==show(quantity[n]) then "all" else g endif)++" of \(n)\n" | n in Items where show(take[n])!="0"])++"\nTotal Weight=\(wTaken) Total Value="++show_float(4,2,wValue)]
</syntaxhighlight>
{{out}}
<pre>
Take all of map
Take all of compass
Take 1 of water
Take all of glucose
Take all of banana
Take all of cheese
Take all of suntan_cream
Take all of waterproof_overclothes
Take all of note_case
Take all of sunglasses
Take all of socks
Total Weight=396 Total Value=1010.00
</pre>
=={{header|Nim}}==
We expand the list of items and apply the 0-1 algorithm.
<syntaxhighlight lang="python"># Knapsack. Recursive solution.
import strformat
import tables
# Description of an item.
type Item = tuple[name: string; weight, value, pieces: int]
# List of available items.
const Items: seq[Item] = @[("map", 9, 150, 1),
("compass", 13, 35, 1),
("water", 153, 200, 2),
("sandwich", 50, 60, 2),
("glucose", 15, 60, 2),
("tin", 68, 45, 3),
("banana", 27, 60, 3),
("apple", 39, 40, 3),
("cheese", 23, 30, 1),
("beer", 52, 10, 3),
("suntan cream", 11, 70, 1),
("camera", 32, 30, 1),
("T-shirt", 24, 15, 2),
("trousers", 48, 10, 2),
("umbrella", 73, 40, 1),
("waterproof trousers", 42, 70, 1),
("waterproof overclothes", 43, 75, 1),
("note-case", 22, 80, 1),
("sunglasses", 7, 20, 1),
("towel", 18, 12, 2),
("socks", 4, 50, 1),
("book", 30, 10, 2)
]
type
# Item numbers (used rather than items themselves).
Number = range[0..Items.high]
# Description of an expanded item.
ExpandedItem = tuple[num: Number; weight, value: int]
# Expanded items management.
proc expandedItems(items: seq[Item]): seq[ExpandedItem] =
## Expand the list of items.
for idx, item in Items:
for _ in 1..item.pieces:
result.add((idx.Number, item.weight, item.value))
const ItemList = expandedItems(Items)
type
# Index in the expanded list.
ExpandedIndex = 0..ItemList.high
# Chosen items and their total value.
Choice = tuple[indexes: set[ExpandedIndex]; weight, value: int]
# Cache used to speed up the search.
var cache: Table[tuple[index, weight: int], Choice]
#---------------------------------------------------------------------------------------------------
proc select(idx, weightLimit: int): Choice =
## Find the best choice starting from item at index "idx".
if idx < 0 or weightLimit == 0:
return
if (idx, weightLimit) in cache:
return cache[(idx, weightLimit)]
let weight = ItemList[idx].weight
if weight > weightLimit:
return select(idx - 1, weightLimit)
# Try by leaving this item and selecting among remaining items.
result = select(idx - 1, weightLimit)
# Try by taking this item and completing with some remaining items.
var result1 = select(idx - 1, weightLimit - weight)
inc result1.value, ItemList[idx].value
# Select the best choice (giving the greater value).
if result1.value > result.value:
result = (result1.indexes + {idx.ExpandedIndex}, result1.weight + weight, result1.value)
cache[(idx, weightLimit)] = result
#---------------------------------------------------------------------------------------------------
let (indexes, weight, value) = select(ItemList.high, 400)
# Count the number of pieces for each item.
var pieces = newSeq[int](Items.len)
for idx in indexes:
inc pieces[ItemList[idx].num]
echo "List of items:"
for num in 0..Items.high:
if pieces[num] > 0:
echo fmt"– {pieces[num]} of {Items[num].pieces} {Items[num].name}"
echo ""
echo "Total weight: ", weight
echo "Total value: ", value
</syntaxhighlight>
{{out}}
<pre>
List of items:
– 1 of 1 map
– 1 of 1 compass
– 1 of 2 water
– 2 of 2 glucose
– 3 of 3 banana
– 1 of 1 cheese
– 1 of 1 suntan cream
– 1 of 1 waterproof overclothes
– 1 of 1 note-case
– 1 of 1 sunglasses
– 1 of 1 socks
Total weight: 396
Total value: 1010
</pre>
=={{header|OOCalc}}==
Line 1,895 ⟶ 2,654:
=={{header|OxygenBasic}}==
<
type KnapSackItem string name,sys dag,value,tag
Line 2,006 ⟶ 2,765:
'
'Weight: 396
</syntaxhighlight>
=={{header|Oz}}==
Using constraint programming.
<
%% maps items to tuples of
%% Weight(hectogram), Value and available Pieces
Line 2,078 ⟶ 2,837:
{System.printInfo "\n"}
{System.showInfo "total value: "#{Value Best}}
{System.showInfo "total weight: "#{Weight Best}}</
{{out}}
<pre>
Line 2,098 ⟶ 2,857:
</pre>
Takes about 3 seconds on a slow netbook.
=={{header|Pascal}}==
{{works with|FPC}}
Dynamic programming solution (tested with FPC 3.2.2).
<syntaxhighlight lang="pascal">
program KnapsackBounded;
{$mode objfpc}{$j-}
uses
SysUtils, Math;
type
TItem = record
Name: string;
Weight, Value, Count: Integer;
end;
const
NUM_ITEMS = 22;
ITEMS: array[0..NUM_ITEMS-1] of TItem = (
(Name: 'map'; Weight: 9; Value: 150; Count: 1),
(Name: 'compass'; Weight: 13; Value: 35; Count: 1),
(Name: 'water'; Weight: 153; Value: 200; Count: 2),
(Name: 'sandwich'; Weight: 50; Value: 60; Count: 2),
(Name: 'glucose'; Weight: 15; Value: 60; Count: 2),
(Name: 'tin'; Weight: 68; Value: 45; Count: 3),
(Name: 'banana'; Weight: 27; Value: 60; Count: 3),
(Name: 'apple'; Weight: 39; Value: 40; Count: 3),
(Name: 'cheese'; Weight: 23; Value: 30; Count: 1),
(Name: 'beer'; Weight: 52; Value: 10; Count: 3),
(Name: 'suntan cream'; Weight: 11; Value: 70; Count: 1),
(Name: 'camera'; Weight: 32; Value: 30; Count: 1),
(Name: 'T-shirt'; Weight: 24; Value: 15; Count: 2),
(Name: 'trousers'; Weight: 48; Value: 10; Count: 2),
(Name: 'umbrella'; Weight: 73; Value: 40; Count: 1),
(Name: 'waterproof trousers'; Weight: 42; Value: 70; Count: 1),
(Name: 'waterproof overclothes'; Weight: 43; Value: 75; Count: 1),
(Name: 'note-case'; Weight: 22; Value: 80; Count: 1),
(Name: 'sunglasses'; Weight: 7; Value: 20; Count: 1),
(Name: 'towel'; Weight: 18; Value: 12; Count: 2),
(Name: 'socks'; Weight: 4; Value: 50; Count: 1),
(Name: 'book'; Weight: 30; Value: 10; Count: 2)
);
MAX_WEIGHT = 400;
var
D: array of array of Integer; //DP matrix
I, W, V, C, MaxWeight: Integer;
begin
SetLength(D, NUM_ITEMS + 1, MAX_WEIGHT + 1);
for I := 0 to High(ITEMS) do
for W := 0 to MAX_WEIGHT do begin
D[I+1, W] := D[I, W];
for C := 1 to ITEMS[I].Count do begin
if ITEMS[I].Weight * C > W then break;
V := D[I, W - ITEMS[I].Weight * C] + ITEMS[I].Value * C;
if V > D[I+1, W] then
D[I+1, W] := V;
end;
end;
W := MAX_WEIGHT;
MaxWeight := 0;
WriteLn('bagged:');
for I := High(ITEMS) downto 0 do begin
V := D[I+1, W];
C := 0;
while V <> D[I, W] + ITEMS[I].Value * C do begin
Dec(W, ITEMS[I].Weight);
Inc(C);
end;
Inc(MaxWeight, C * ITEMS[I].Weight);
if C <> 0 then
WriteLn(' ', C, ' ', ITEMS[I].Name);
end;
WriteLn('value = ', D[NUM_ITEMS, MAX_WEIGHT]);
WriteLn('weight = ', MaxWeight);
end.
</syntaxhighlight>
{{out}}
<pre>
bagged:
1 socks
1 sunglasses
1 note-case
1 waterproof overclothes
1 suntan cream
1 cheese
3 banana
2 glucose
1 water
1 compass
1 map
value = 1010
weight = 396
</pre>
=={{header|Perl}}==
Recursive solution with caching.
<
use strict;
Line 2,173 ⟶ 3,027:
}
}
print "Value: $v; Weight: $w\n";</
{{out}}
<pre>1 of map
Line 2,187 ⟶ 3,041:
1 of socks
Value: 1010; Weight: 396</pre>
=={{header|Phix}}==
===Very dumb and very slow brute force version===
Of no practical use, except for comparison against improvements.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">goodies</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"map"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">150</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"compass"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">13</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">35</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"sandwich"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">50</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">60</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"glucose"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">15</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">60</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"tin"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">68</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">45</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"banana"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">27</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">60</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"apple"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">39</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">40</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"cheese"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">23</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"beer"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">52</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"suntan cream"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">70</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"water"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">153</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">200</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"camera"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">32</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"T-shirt"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">24</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">15</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"trousers"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">48</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"umbrella"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">73</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">40</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"waterproof trousers"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">42</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">70</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"waterproof overclothes"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">43</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">75</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"note-case"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">22</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">80</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"sunglasses"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">20</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"towel"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">18</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"socks"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">50</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"book"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">knapsack</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">max_weight</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">at</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">best_points</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">points</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">best_choices</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span> <span style="color: #000000;">choices</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">act_weight</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">sub_weight</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">at</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{?,</span><span style="color: #000000;">witem</span><span style="color: #0000FF;">,</span><span style="color: #000000;">pitem</span><span style="color: #0000FF;">,</span><span style="color: #000000;">imax</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">goodies</span><span style="color: #0000FF;">[</span><span style="color: #000000;">at</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">imax</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">wlim</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">max_weight</span><span style="color: #0000FF;">-</span><span style="color: #000000;">i</span><span style="color: #0000FF;">*</span><span style="color: #000000;">witem</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">wlim</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sub_weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">choices</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">knapsack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wlim</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">at</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">points</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">*</span><span style="color: #000000;">pitem</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">></span><span style="color: #000000;">best_points</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">best_points</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">points</span>
<span style="color: #000000;">best_choices</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">choices</span><span style="color: #0000FF;">)&</span><span style="color: #000000;">i</span>
<span style="color: #000000;">act_weight</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sub_weight</span><span style="color: #0000FF;">+</span><span style="color: #000000;">i</span><span style="color: #0000FF;">*</span><span style="color: #000000;">witem</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">best_points</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">act_weight</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">best_choices</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">knapsack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">400</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">goodies</span><span style="color: #0000FF;">))</span> <span style="color: #000080;font-style:italic;">-- {points,act_weight,choices}</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">weight</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">witem</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">points</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pitem</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">idesc</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">goodies</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">3</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">idesc</span><span style="color: #0000FF;">,</span><span style="color: #000000;">witem</span><span style="color: #0000FF;">,</span><span style="color: #000000;">pitem</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">goodies</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%d %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">idesc</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">weight</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">*</span><span style="color: #000000;">witem</span>
<span style="color: #000000;">points</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">*</span><span style="color: #000000;">pitem</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- sanity check</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Value %d, weight %g [%3.2fs]\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">weight</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">})</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 2,345 ⟶ 3,130:
Much faster but limited to integer weights
{{trans|C}}
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">items</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"map"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">150</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"compass"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">13</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">35</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"water"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">153</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">200</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"sandwich"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">50</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">60</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"glucose"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">15</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">60</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"tin"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">68</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">45</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"banana"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">27</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">60</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"apple"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">39</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">40</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"cheese"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">23</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"beer"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">52</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"suntan cream"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">70</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"camera"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">32</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"T-shirt"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">24</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">15</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"trousers"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">48</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"umbrella"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">73</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">40</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"waterproof trousers"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">42</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">70</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"waterproof overclothes"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">43</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">75</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"note-case"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">22</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">80</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"sunglasses"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">20</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"towel"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">18</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"socks"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">50</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"book"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">};</span>
<span style="color: #004080;">sequence</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">names</span><span style="color: #0000FF;">,</span><span style="color: #000000;">weights</span><span style="color: #0000FF;">,</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">counts</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">columnize</span><span style="color: #0000FF;">(</span><span style="color: #000000;">items</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">items</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">knapsack</span><span style="color: #0000FF;">(</span><span style="color: #004080;">int</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">v</span>
<span style="color: #000080;font-style:italic;">-- m is the achievable points matrix:
-- Note that Phix uses 1-based indexes, so m[1][1]
-- actually holds points for 0 items of weight 0,
-- and m[n+1][w+1] is for n items at weight w.</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">w</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span><span style="color: #000000;">n</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span> <span style="color: #000080;font-style:italic;">-- (0 to w really)</span>
<span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">counts</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">*</span><span style="color: #000000;">weights</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]></span><span style="color: #000000;">j</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">-</span><span style="color: #000000;">k</span><span style="color: #0000FF;">*</span><span style="color: #000000;">weights</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]+</span><span style="color: #000000;">k</span><span style="color: #0000FF;">*</span><span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">></span><span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">v</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">j</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- (w -> 0 really)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">n</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">k</span><span style="color: #0000FF;">*</span><span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">j</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">weights</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">s</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">tc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tw</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tv</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">knapsack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">400</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">si</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">si</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%-22s %5d %5d %5d\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">names</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">*</span><span style="color: #000000;">weights</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">*</span><span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]})</span>
<span style="color: #000000;">tc</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">si</span>
<span style="color: #000000;">tw</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">*</span><span style="color: #000000;">weights</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">tv</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">*</span><span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%-22s %5d %5d %5d\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"count, weight, points:"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tc</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tw</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tv</span><span style="color: #0000FF;">})</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 2,441 ⟶ 3,229:
would obviously increase dramatically. A naive cache could also suffer similarly, if it retained
duplicate solutions for w=15.783, 15.784, 15.785, and everything in between.
Using a (bespoke) range cache solves this problem, although the simplistic version given could probably be improved with a binary search or similar. It also significantly reduces the workload; for instance if you find a solution for 170 that actually weighs 150 then any subsequent query in 150..170 requires zero work, unlike the naive cache and dp solutions.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\knapsackB.exw</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">enum</span> <span style="color: #000000;">HI</span><span style="color: #0000FF;">,</span><span style="color: #000000;">PTS</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ACTW</span><span style="color: #0000FF;">,</span><span style="color: #000000;">SOLN</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">range_cache</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">cache_entries</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">add_range</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">at</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">weight</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">actual_weight</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">soln</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">actual_weight</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">weight</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range_cache</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">at</span> <span style="color: #008080;">do</span> <span style="color: #000080;font-style:italic;">-- (while too small do)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">at</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">range_cache</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range_cache</span><span style="color: #0000FF;">,{{</span><span style="color: #000000;">weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">actual_weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">}})</span>
<span style="color: #000000;">cache_entries</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">range_cache</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range_cache</span><span style="color: #0000FF;">,{})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">lastHI</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range_cache</span><span style="color: #0000FF;">[</span><span style="color: #000000;">at</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">rcati</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">range_cache</span><span style="color: #0000FF;">[</span><span style="color: #000000;">at</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">weight</span><span style="color: #0000FF;">=</span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ACTW</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">PTS</span><span style="color: #0000FF;">..</span><span style="color: #000000;">SOLN</span><span style="color: #0000FF;">]=={</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">actual_weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">weight</span><span style="color: #0000FF;"><</span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ACTW</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- (we cannot extend an existing range down...)</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SOLN</span><span style="color: #0000FF;">])</span>
<span style="color: #000080;font-style:italic;">-- insert a new range</span>
<span style="color: #000000;">range_cache</span><span style="color: #0000FF;">[</span><span style="color: #000000;">at</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">actual_weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">}}</span>
<span style="color: #000000;">cache_entries</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">soln</span><span style="color: #0000FF;">=</span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SOLN</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">PTS</span><span style="color: #0000FF;">..</span><span style="color: #000000;">SOLN</span><span style="color: #0000FF;">]=={</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">actual_weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">weight</span><span style="color: #0000FF;">></span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">HI</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- extend existing range up</span>
<span style="color: #000000;">rcati</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #000000;">range_cache</span><span style="color: #0000FF;">[</span><span style="color: #000000;">at</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">HI</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">weight</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">weight</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">HI</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"duplicate solution??"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (or discard as below)
-- return -- (discard)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ACTW</span><span style="color: #0000FF;">]></span><span style="color: #000000;">lastHI</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">lastHI</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">HI</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">range_cache</span><span style="color: #0000FF;">[</span><span style="color: #000000;">at</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range_cache</span><span style="color: #0000FF;">[</span><span style="color: #000000;">at</span><span style="color: #0000FF;">],{</span><span style="color: #000000;">weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">actual_weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">cache_entries</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">in_range</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">at</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">weight</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">at</span><span style="color: #0000FF;"><=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range_cache</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range_cache</span><span style="color: #0000FF;">[</span><span style="color: #000000;">at</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">rcati</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">range_cache</span><span style="color: #0000FF;">[</span><span style="color: #000000;">at</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">weight</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">HI</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">weight</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ACTW</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">rcati</span><span style="color: #0000FF;">[</span><span style="color: #000000;">PTS</span><span style="color: #0000FF;">..</span><span style="color: #000000;">SOLN</span><span style="color: #0000FF;">]</span> <span style="color: #000080;font-style:italic;">-- {pts,act_weight,soln}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{}</span> <span style="color: #000080;font-style:italic;">-- (no suitable cache entry found)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">goodies</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">({</span>
<span style="color: #000080;font-style:italic;">-- item weight value pieces</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"map"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">150</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"compass"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">13</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">35</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"sandwich"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">50</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">60</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"glucose"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">15</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">60</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"tin"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">68</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">45</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"banana"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">27</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">60</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"apple"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">39</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">40</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"cheese"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">23</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"beer"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">52</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"suntan cream"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">70</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"water"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">153</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">200</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"camera"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">32</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"T-shirt"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">24</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">15</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"trousers"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">48</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"umbrella"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">73</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">40</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"waterproof trousers"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">42</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">70</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"waterproof overclothes"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">43</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">75</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"note-case"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">22</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">80</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"sunglasses"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">20</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"towel"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">18</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"socks"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">50</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"book"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">}})</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">cache_hits</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">cache_misses</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">knapsack</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">max_weight</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">at</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">best_points</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">points</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">best_choices</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span> <span style="color: #000000;">choices</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">act_weight</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">sub_weight</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">at</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">soln</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">in_range</span><span style="color: #0000FF;">(</span><span style="color: #000000;">at</span><span style="color: #0000FF;">,</span><span style="color: #000000;">max_weight</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">cache_hits</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">soln</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">cache_misses</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{?,</span><span style="color: #000000;">witem</span><span style="color: #0000FF;">,</span><span style="color: #000000;">pitem</span><span style="color: #0000FF;">,</span><span style="color: #000000;">imax</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">goodies</span><span style="color: #0000FF;">[</span><span style="color: #000000;">at</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">best_choices</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">at</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">imax</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">wlim</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">max_weight</span><span style="color: #0000FF;">-</span><span style="color: #000000;">i</span><span style="color: #0000FF;">*</span><span style="color: #000000;">witem</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">wlim</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sub_weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">choices</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">knapsack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wlim</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">at</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">points</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">*</span><span style="color: #000000;">pitem</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">></span><span style="color: #000000;">best_points</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">best_points</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">points</span>
<span style="color: #000000;">best_choices</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">choices</span><span style="color: #0000FF;">)&</span><span style="color: #000000;">i</span>
<span style="color: #000000;">act_weight</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sub_weight</span><span style="color: #0000FF;">+</span><span style="color: #000000;">i</span><span style="color: #0000FF;">*</span><span style="color: #000000;">witem</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">add_range</span><span style="color: #0000FF;">(</span><span style="color: #000000;">at</span><span style="color: #0000FF;">,</span><span style="color: #000000;">max_weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">act_weight</span><span style="color: #0000FF;">,</span><span style="color: #000000;">best_points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">best_choices</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">best_points</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">act_weight</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">best_choices</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">knapsack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">400</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">goodies</span><span style="color: #0000FF;">))</span> <span style="color: #000080;font-style:italic;">-- {points,act_weight,choices}</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">weight</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">witem</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">points</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pitem</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">idesc</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">choices</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">3</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">goodies</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">choices</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">idesc</span><span style="color: #0000FF;">,</span><span style="color: #000000;">witem</span><span style="color: #0000FF;">,</span><span style="color: #000000;">pitem</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">goodies</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%d %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">idesc</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">weight</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">*</span><span style="color: #000000;">witem</span>
<span style="color: #000000;">points</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">*</span><span style="color: #000000;">pitem</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">({</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">weight</span><span style="color: #0000FF;">}==</span><span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">2</span><span style="color: #0000FF;">])</span> <span style="color: #000080;font-style:italic;">-- sanity check</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Value %d, weight %g [%3.2fs]:\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">weight</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"cache_entries:%d, hits:%d, misses:%d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">cache_entries</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cache_hits</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cache_misses</span><span style="color: #0000FF;">})</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 2,602 ⟶ 3,396:
</pre>
Even on this simple integer-only case, range cache reduces cache size better than 10-fold and effort 6-fold.<br>
We also know the dp solution matrix has 9223 entries, admittedly each being much smaller than a cache entry.<br>
And finally CACHE_NONE (the dumb version): (as above but ending)
<pre>
Value 1010, weight 396 [18.14s]
cache_entries:0, hits:0, misses:33615741
</pre>
=={{header|Picat}}==
<syntaxhighlight lang="picat">import mip,util.
go =>
data(AllItems,MaxWeight),
[Items,Weights,Values,Pieces] = transpose(AllItems),
knapsack_bounded(Weights,Values,Pieces,MaxWeight, X,TotalWeight,TotalValue),
print_solution(Items,Weights,Values, X,TotalWeight,TotalValue),
nl.
% Print the solution
print_solution(Items,Weights,Values, X,TotalWeight,TotalValue) ?=>
println("\nThese are the items to pick:"),
println(" Item Weight Value"),
foreach(I in 1..Items.len)
if X[I] > 0 then
printf("* %d %-29w %3d %3d\n", X[I],Items[I],Weights[I],Values[I])
end
end,
nl,
printf("Total weight: %d\n", TotalWeight),
printf("Total value: %d\n", TotalValue),
nl.
% Solve knapsack problem
knapsack_bounded(Weights,Values,Pieces,MaxWeight, X,TotalWeight,TotalValue) =>
NumItems = length(Weights),
% Variables
MaxPieces = max(Pieces),
X = new_list(NumItems),
X :: 0..MaxPieces,
% Constraints
SumValues = sum(Values),
TotalValue :: 0..SumValues,
TotalWeight :: 0..MaxWeight,
scalar_product(Weights,X,TotalWeight),
scalar_product(Values,X,TotalValue),
TotalWeight #<= MaxWeight,
% Check number of pieces
foreach({XVal,Piece} in zip(X,Pieces))
XVal #=< Piece
end,
% Search
Vars = X ++ [TotalWeight, TotalValue],
solve($[max(TotalValue),down],Vars).
% data
data(Items,MaxWeight) =>
Items =
% Item Weight Value Pieces
[["map", 9, 150, 1],
["compass", 13, 35, 1],
["water", 153, 200, 2],
["sandwich", 50, 60, 2],
["glucose", 15, 60, 2],
["tin", 68, 45, 3],
["banana", 27, 60, 3],
["apple", 39, 40, 3],
["cheese", 23, 30, 1],
["beer", 52, 10, 3],
["suntancream", 11, 70, 1],
["camera", 32, 30, 1],
["T-shirt", 24, 15, 2],
["trousers", 48, 10, 2],
["umbrella", 73, 40, 1],
["waterproof trousers", 42, 70, 1],
["waterproof overclothes", 43, 75, 1],
["note-case", 22, 80, 1],
["sunglasses", 7, 20, 1],
["towel", 18, 12, 2],
["socks", 4, 50, 1],
["book", 30, 10, 2]],
MaxWeight = 400.</syntaxhighlight>
{{out}}
<pre>These are the items to pick:
Item Weight Value
* 1 map 9 150
* 1 compass 13 35
* 1 water 153 200
* 2 glucose 15 60
* 3 banana 27 60
* 1 cheese 23 30
* 1 suntancream 11 70
* 1 waterproof overclothes 43 75
* 1 note-case 22 80
* 1 sunglasses 7 20
* 1 socks 4 50
Total weight: 396
Total value: 1010</pre>
=={{header|PicoLisp}}==
<
("map" 9 150 1) ("compass" 13 35 1)
("water" 153 200 3) ("sandwich" 50 60 2)
Line 2,640 ⟶ 3,536:
(for I K
(apply tab I (3 -24 6 6) NIL) )
(tab (27 6 6) NIL (sum cadr K) (sum caddr K)) )</
{{out}}
<pre> map 9 150
Line 2,663 ⟶ 3,559:
{{libheader|clpfd}}
Library clpfd is written by <b>Markus Triska</b>. Takes about 3 seconds to compute the best solution.
<
% tuples (name, weights, value, nb pieces).
Line 2,738 ⟶ 3,634:
sformat(W3, A3, [V]),
format('~w~w~w~w~n', [W0,W1,W2,W3]),
print_results(A1, A2, A3, T, TR, WM, VM).</
{{out}}
<pre> ?- knapsack.
Line 2,758 ⟶ 3,654:
===Library simplex===
Library simplex is written by <b>Markus Triska</b>. Takes about 10 seconds to compute the best solution.
<
% tuples (name, weights, value, pieces).
knapsack :-
Line 2,837 ⟶ 3,733:
W2 is W1 + X * W,
V2 is V1 + X * V),
print_results(S, A1, A2, A3, T, TN, W2, V2).</
=={{header|Python}}==
Not as [[Knapsack problem/0-1#Python|dumb a search]] over all possible combinations under the maximum allowed weight:
<
from collections import namedtuple
def anyvalidcomb(items, maxwt, val=0, wt=0):
' All combinations below the maxwt '
if not items:
Line 2,851 ⟶ 3,746:
else:
this, *items = items # car, cdr
for n in range(this.number + 1):
if w > maxwt:
break
this_comb
for comb, value, weight in anyvalidcomb(items, maxwt, v, w):
yield this_comb + comb, value, weight
maxwt = 400
Line 2,888 ⟶ 3,784:
) ]
bagged = max( anyvalidcomb(items, maxwt), key=lambda c: (c[VAL], -c[WT])) # max val or min wt if values equal
print("Bagged the following %i items
print("for a total value of %i and a total weight of %i" % bagged[1:])</syntaxhighlight>
{{out}}
<pre>Bagged the following 14 items
Line 2,909 ⟶ 3,804:
===Dynamic programming solution===
This is much faster. It expands the multiple possible instances of an item into individual instances then applies the zero-one dynamic knapsack solution:
<
try:
Line 2,974 ⟶ 3,869:
for item,grp in groupby(sorted(bagged))))
print("for a total value of %i and a total weight of %i" % (
sum(item[2] for item in bagged), sum(item[1] for item in bagged)))</
===Non-zero-one solution===
<
}
item_keys = list(items.keys())
#cache: could just use memoize module, but explicit caching is clearer
def choose_item(weight, idx, cache):
if idx < 0: return 0, []
k = (weight, idx)
if k in cache: return cache[k]
name, w, v, qty = item_keys[idx], *items[item_keys[idx]]
best_v, best_list = 0, []
for i in range(0, qty + 1):
wlim = weight - i * w
if wlim < 0: break
val, taken = choose_item(wlim, idx - 1, cache)
if val + i * v > best_v:
best_v = val + i * v
best_list = taken[:]
best_list.append((i, name))
cache[k] = [best_v, best_list]
return best_v, best_list
v, lst = choose_item(400, len(items) - 1, {})
w = 0
for
if cnt > 0:
print
w = w + items[
print("Total weight:", w, "Value:", v)</syntaxhighlight>
=={{header|R}}==
Reading in task via web scraping.
<syntaxhighlight lang="r">library(tidyverse)
library(rvest)
task_html= read_html("http://rosettacode.org/wiki/Knapsack_problem/Bounded")
task_table= html_nodes(html, "table")[[1]] %>%
html_table(table, header= T, trim= T) %>%
set_names(c("items", "weight", "value", "pieces")) %>%
filter(items != "knapsack") %>%
mutate(weight= as.numeric(weight),
value= as.numeric(value),
pieces= as.numeric(pieces))</syntaxhighlight>
Solution of the task using genetic algorithm.
<syntaxhighlight lang="r">library(rgenoud)
fitness= function(x= rep(1, nrow(task_table))){
total_value= sum(task_table$value * x)
total_weight= sum(task_table$weight * x)
ifelse(total_weight <= 400, total_value, 400-total_weight)
}
allowed= matrix(c(rep(0, nrow(task_table)), task_table$pieces), ncol = 2)
set.seed(42)
evolution= genoud(fn= fitness,
nvars= nrow(allowed),
max= TRUE,
pop.size= 10000,
data.type.int= TRUE,
Domains= allowed)
cat("Value: ", evolution$value, "\n")
cat("Weight:", sum(task_table$weight * evolution$par), "dag", "\n")
data.frame(item= task_table$items, pieces= as.integer(solution)) %>%
filter(solution> 0)</syntaxhighlight>
{{out}}
<pre>
Value: 1010
Weight: 396 dag
item pieces
1 map 1
2 compass 1
3 sandwich 1
4 glucose 2
5 banana 3
6 apple 2
7 cheese 1
8 suntan cream 1
9 waterproof overclothes 1
10 note-case 1
11 sunglasses 1
12 towel 1
13 socks 1
</pre>
=={{header|Racket}}==
The algorithm is nearly a direct translation of Haskell's array-based implementation. However, the data is taken from the webpage itself.
<syntaxhighlight lang="racket">
#lang racket
(require net/url html xml xml/path)
Line 3,126 ⟶ 4,083:
(match-let ([(solution value choices) (best (vector->list (solution-vector capacity)))])
(solution value (filter (compose positive? choice-count) choices))))
</syntaxhighlight>
{{out}}
Line 3,145 ⟶ 4,102:
(choice "map" 1)))
</pre>
=={{header|Raku}}==
(formerly Perl 6)
==== Original ====
Recursive algorithm, with cache. Idiomatic code style, using multi-subs and a class.
{{works with|Rakudo|2017.01}}
<syntaxhighlight lang="raku" line>my class KnapsackItem { has $.name; has $.weight; has $.unit; }
multi sub pokem ([], $, $v = 0) { $v }
multi sub pokem ([$, *@], 0, $v = 0) { $v }
multi sub pokem ([$i, *@rest], $w, $v = 0) {
my $key = "{+@rest} $w $v";
(state %cache){$key} or do {
my @skip = pokem @rest, $w, $v;
if $w >= $i.weight { # next one fits
my @put = pokem @rest, $w - $i.weight, $v + $i.unit;
return (%cache{$key} = |@put, $i.name).list if @put[0] > @skip[0];
}
return (%cache{$key} = |@skip).list;
}
}
my $MAX_WEIGHT = 400;
my @table = flat map -> $name, $weight, $unit, $count {
KnapsackItem.new( :$name, :$weight, :$unit ) xx $count;
},
'map', 9, 150, 1,
'compass', 13, 35, 1,
'water', 153, 200, 2,
'sandwich', 50, 60, 2,
'glucose', 15, 60, 2,
'tin', 68, 45, 3,
'banana', 27, 60, 3,
'apple', 39, 40, 3,
'cheese', 23, 30, 1,
'beer', 52, 10, 3,
'suntan cream', 11, 70, 1,
'camera', 32, 30, 1,
'T-shirt', 24, 15, 2,
'trousers', 48, 10, 2,
'umbrella', 73, 40, 1,
'waterproof trousers', 42, 70, 1,
'waterproof overclothes', 43, 75, 1,
'note-case', 22, 80, 1,
'sunglasses', 7, 20, 1,
'towel', 18, 12, 2,
'socks', 4, 50, 1,
'book', 30, 10, 2
;
my ($value, @result) = pokem @table, $MAX_WEIGHT;
(my %hash){$_}++ for @result;
say "Value = $value";
say "Tourist put in the bag:";
say " # ITEM";
for %hash.sort -> $item {
say " {$item.value} {$item.key}";
}</syntaxhighlight>
{{out}}
<pre>Value = 1010
Tourist put in the bag:
# ITEM
3 banana
1 cheese
1 compass
2 glucose
1 map
1 note-case
1 socks
1 sunglasses
1 suntan cream
1 water
1 waterproof overclothes</pre>
==== Faster alternative ====
Also recursive, with cache, but substantially faster. Code more generic (ported from Perl solution).
<syntaxhighlight lang="raku" line>my $raw = qq:to/TABLE/;
map 9 150 1
compass 13 35 1
water 153 200 2
sandwich 50 60 2
glucose 15 60 2
tin 68 45 3
banana 27 60 3
apple 39 40 3
cheese 23 30 1
beer 52 10 1
suntancream 11 70 1
camera 32 30 1
T-shirt 24 15 2
trousers 48 10 2
umbrella 73 40 1
w_trousers 42 70 1
w_overcoat 43 75 1
note-case 22 80 1
sunglasses 7 20 1
towel 18 12 2
socks 4 50 1
book 30 10 2
TABLE
my @items;
for split(["\n", /\s+/], $raw, :skip-empty) -> $n,$w,$v,$q {
@items.push: %{ name => $n, weight => $w, value => $v, quant => $q}
}
my $max_weight = 400;
sub pick ($weight, $pos) {
state %cache;
return 0, 0 if $pos < 0 or $weight <= 0;
my $key = $weight ~ $pos;
%cache{$key} or do {
my %item = @items[$pos];
my ($bv, $bi, $bw, @bp) = (0, 0, 0);
for 0 .. %item{'quant'} -> $i {
last if $i * %item{'weight'} > $weight;
my ($v, $w, @p) = pick($weight - $i * %item{'weight'}, $pos - 1);
next if ($v += $i * %item{'value'}) <= $bv;
($bv, $bi, $bw, @bp) = ($v, $i, $w, |@p);
}
%cache{$key} = $bv, $bw + $bi * %item{'weight'}, |@bp, $bi;
}
}
my ($v, $w, @p) = pick($max_weight, @items.end);
{ say "{@p[$_]} of @items[$_]{'name'}" if @p[$_] } for 0 .. @p.end;
say "Value: $v Weight: $w";</syntaxhighlight>
{{out}}
<pre>1 of map
1 of compass
1 of water
2 of glucose
3 of banana
1 of cheese
1 of suntancream
1 of w_overcoat
1 of note-case
1 of sunglasses
1 of socks
Value: 1010 Weight: 396</pre>
=={{header|REXX}}==
Line 3,152 ⟶ 4,255:
<br>"unrolled" and converted into discrete combination checks (based on the number of items). The unused combinatorial
<br>checks were discarded and only the pertinent code was retained.
<
call @gen /*generate items and initializations. */
call @sort /*sort items by decreasing their weight*/
Line 3,307 ⟶ 4,410:
do j37=j36+(j36>0) to h;if w.j37+w36>m then iterate j36;w37=w36+w.j37;z37=z36+v.j37;if z37>$ then call j? 37
end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end
end;end;end;end;end;end;end;end;end;end; return /* [↑] there is one END for each DO loop.*/</
'''output'''
<pre>
Line 3,366 ⟶ 4,469:
{{trans|Python}}
<
# Item struct to represent each item in the problem
Struct.new('Item', :name, :weight, :value, :count)
Line 3,426 ⟶ 4,529:
p "Total weight: #{w}, Value: #{val}"
</syntaxhighlight>
=={{header|SAS}}==
Use MILP solver in SAS/OR:
<
data mydata;
input item $1-23 weight value pieces;
Line 3,480 ⟶ 4,583:
print TotalValue;
print {i in ITEMS: NumSelected[i].sol > 0.5} NumSelected;
quit;</
Output:
Line 3,503 ⟶ 4,606:
=={{header|Sidef}}==
{{trans|Perl}}
<
map 9 150 1
compass 13 35 1
Line 3,569 ⟶ 4,672:
say "#{p[i]} of #{items[i].name}" if p[i].is_pos
}
say "Value: #{v}; Weight: #{w}"</
{{out}}
<pre>
Line 3,584 ⟶ 4,687:
1 of socks
Value: 1010; Weight: 396
</pre>
=={{header|Swift}}==
{{trans|Python}}
<syntaxhighlight lang="swift">public struct KnapsackItem: Hashable {
public var name: String
public var weight: Int
public var value: Int
public init(name: String, weight: Int, value: Int) {
self.name = name
self.weight = weight
self.value = value
}
}
public func knapsack(items: [KnapsackItem], limit: Int) -> [KnapsackItem] {
var table = Array(repeating: Array(repeating: 0, count: limit + 1), count: items.count + 1)
for j in 1...items.count {
let item = items[j-1]
for w in 1...limit {
if item.weight > w {
table[j][w] = table[j-1][w]
} else {
table[j][w] = max(table[j-1][w], table[j-1][w-item.weight] + item.value)
}
}
}
var result = [KnapsackItem]()
var w = limit
for j in stride(from: items.count, to: 0, by: -1) where table[j][w] != table[j-1][w] {
let item = items[j-1]
result.append(item)
w -= item.weight
}
return result
}
typealias GroupedItem = (name: String, weight: Int, val: Int, n: Int)
let groupedItems: [GroupedItem] = [
("map", 9, 150, 1),
("compass", 13, 35, 1),
("water", 153, 200, 3),
("sandwich", 50, 60, 2),
("glucose", 15, 60, 2),
("tin", 68, 45, 3),
("banana", 27, 60, 3),
("apple", 39, 40, 3),
("cheese", 23, 30, 1),
("beer", 52, 10, 3),
("suntan cream", 11, 70, 1),
("camera", 32, 30, 1),
("t-shirt", 24, 15, 2),
("trousers", 48, 10, 2),
("umbrella", 73, 40, 1),
("waterproof trousers", 42, 70, 1),
("waterproof overclothes", 43, 75, 1),
("note-case", 22, 80, 1),
("sunglasses", 7, 20, 1),
("towel", 18, 12, 2),
("socks", 4, 50, 1),
("book", 30, 10, 2)
]
let items = groupedItems.flatMap({item in
(0..<item.n).map({_ in KnapsackItem(name: item.name, weight: item.weight, value: item.val) })
})
let bagged = knapsack(items: items, limit: 400)
let (totalVal, totalWeight) = bagged.reduce((0, 0), {cur, item in (cur.0 + item.value, cur.1 + item.weight) })
print("Bagged the following \(bagged.count) items:")
for item in bagged {
print("\t\(item.name)")
}
print("For a total value of \(totalVal) and weight of \(totalWeight)")</syntaxhighlight>
{{out}}
<pre>Bagged the following 14 items:
socks
sunglasses
note-case
waterproof overclothes
suntan cream
cheese
banana
banana
banana
glucose
glucose
water
compass
map
For a total value of 1010 and weight of 396
</pre>
=={{header|Tcl}}==
Classic dumb search algorithm:
<
set items {
{map 9 150 1}
Line 3,674 ⟶ 4,884:
foreach {count item} [countednames $best] {
puts "\t$count * $item"
}</
{{out}}
<pre>
Line 3,695 ⟶ 4,905:
Instead of an ''ad-hoc'' solution, we can convert this task to a
[[wp:Mixed_integer_programming#Integer_unknowns|mixed integer programming]] problem instance and solve it with the [http://lpsolve.sourceforge.net lpsolve] library, which is callable in Ursala.
<
#import flo
#import lin
Line 3,738 ⟶ 4,948:
#show+
main = format solution system items</
The <code>linear_system$[</code>...<code>]</code> function takes the item list as an argument and returns a data structure with the following fields, which is passed to the <code>solution</code> function, which calls the <code>lpsolve</code> routines.
* <code>integers</code> declares that all variables in the list take integer values
Line 3,758 ⟶ 4,968:
1 water
1 waterproof overclothes</pre>
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./fmt" for Fmt
class Item {
construct new(name, weight, value, count) {
_name = name
_weight = weight
_value = value
_count = count
}
name { _name }
weight { _weight }
value { _value }
count { _count }
}
var items = [
Item.new("map", 9, 150, 1),
Item.new("compass", 13, 35, 1),
Item.new("water", 153, 200, 2),
Item.new("sandwich", 50, 60, 2),
Item.new("glucose", 15, 60, 2),
Item.new("tin", 68, 45, 3),
Item.new("banana", 27, 60, 3),
Item.new("apple", 39, 40, 3),
Item.new("cheese", 23, 30, 1),
Item.new("beer", 52, 10, 3),
Item.new("suntan cream", 11, 70, 1),
Item.new("camera", 32, 30, 1),
Item.new("T-shirt", 24, 15, 2),
Item.new("trousers", 48, 10, 2),
Item.new("umbrella", 73, 40, 1),
Item.new("waterproof trousers", 42, 70, 1),
Item.new("waterproof overclothes", 43, 75, 1),
Item.new("note-case", 22, 80, 1),
Item.new("sunglasses", 7, 20, 1),
Item.new("towel", 18, 12, 2),
Item.new("socks", 4, 50, 1),
Item.new("book", 30, 10, 2)
]
var n = items.count
var maxWeight = 400
var knapsack = Fn.new { |w|
var m = List.filled(n + 1, null)
for (i in 0..n) m[i] = List.filled(w + 1, 0)
for (i in 1..n) {
for (j in 0..w) {
m[i][j] = m[i-1][j]
for (k in 1..items[i - 1].count) {
if (k * items[i - 1].weight > j) break
var v = m[i - 1][j - k * items[i - 1].weight] + k * items[i - 1].value
if (v > m[i][j]) m[i][j] = v
}
}
}
var s = List.filled(n, 0)
var j = w
for (i in n..1) {
var v = m[i][j]
var k = 0
while (v != m[i - 1][j] + k * items[i - 1].value) {
s[i - 1] = s[i - 1] + 1
j = j - items[i - 1].weight
k = k + 1
}
}
return s
}
var s = knapsack.call(maxWeight)
System.print("Item Chosen Weight Value Number")
System.print("--------------------- ------ ----- ------")
var itemCount = 0
var sumWeight = 0
var sumValue = 0
var sumNumber = 0
for (i in 0... n) {
if (s[i] != 0) {
itemCount = itemCount + 1
var name = items[i].name
var number = s[i]
var weight = items[i].weight * number
var value = items[i].value * number
sumNumber = sumNumber + number
sumWeight = sumWeight + weight
sumValue = sumValue + value
Fmt.print("$-22s $3d $4d $2d", name, weight, value, number)
}
}
System.print("--------------------- ------ ----- ------")
Fmt.print("Items chosen $d $3d $4d $2d", itemCount, sumWeight, sumValue, sumNumber)</syntaxhighlight>
{{out}}
<pre>
Item Chosen Weight Value Number
--------------------- ------ ----- ------
map 9 150 1
compass 13 35 1
water 153 200 1
glucose 30 120 2
banana 81 180 3
cheese 23 30 1
suntan cream 11 70 1
waterproof overclothes 43 75 1
note-case 22 80 1
sunglasses 7 20 1
socks 4 50 1
--------------------- ------ ----- ------
Items chosen 11 396 1010 14
</pre>
=={{header|zkl}}==
{{trans|Haskell}}
<
[1..c].reduce(fcn(list,i,nm,w,v,old){
wi,left,right:=w*i,list[0,wi],list[wi,*];
Line 3,768 ⟶ 5,094:
fcn([(v1,_)]a,[(v2,_)]b){ v1>v2 and a or b },new));
},old,nm,w,v,old);
}//--> new list</
<
T("apple", 39, 40,3),T("banana", 27,60,3),
T("beer", 52, 10,3),T("book", 30,10,2),T("camera", 32, 30,1),
Line 3,782 ⟶ 5,108:
'wrap(nm,n){ items[items.filter1n(fcn(it,nm){ it[0]==nm },nm)][1]*n })
.sum(0)
};</
<
knapsack:=items.reduce(addItem,(MAX_WEIGHT).pump(List,T(0,T).copy))[-1];
knapsack.toString(*).println(weight(knapsack));</
{{out}}
<pre>
|