Data update

This commit is contained in:
Ingy döt Net 2026-04-30 12:34:36 -04:00
parent 4bb20c9b71
commit cbaf4c4b64
12390 changed files with 318560 additions and 27248 deletions

View file

@ -0,0 +1,143 @@
with Ada.Text_IO;
procedure Knapsack_Bounded is
subtype Item_Name is String (1 .. 22);
type Item_Weight is new Natural;
type Item_Value is new Natural;
type Item_Count is new Natural;
type Item_Pool is record
Name : Item_Name;
Weight : Item_Weight;
Value : Item_Value;
Count : Item_Count;
end record;
type Item_Bag is array (1 .. 22) of Item_Pool;
Candidates : constant Item_Bag :=
(
("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)
);
Capacity : constant Item_Weight := 400;
Answer : Item_Bag;
type Item_Table is
array (Item_Bag'First - 1 .. Item_Bag'Last,
Item_Weight'First .. Capacity) of Item_Value;
Working_Table : Item_Table := (others => (others => 0));
procedure Fill_Table is
Item : Item_Pool;
V, Max_Value : Item_Value;
W : Item_Weight;
begin
for I in Candidates'Range loop
Item := Candidates (I);
for J in Working_Table'Range (2) loop
Max_Value := Working_Table (I - 1, J);
for K in 1 .. Item.Count loop
V := Item_Value (K) * Item.Value;
W := Item_Weight (K) * Item.Weight;
if W <= J then
Max_Value := Item_Value'Max
(Max_Value, Working_Table (I - 1, J - W) + V);
end if;
end loop;
Working_Table (I, J) := Max_Value;
end loop;
end loop;
end Fill_Table;
procedure Trace_Answer is
Cap : Item_Weight := Capacity;
Count : Item_Count;
W, Weight : Item_Weight;
V, Max_Value : Item_Value;
begin
for I in reverse Answer'Range loop
Answer (I) := Candidates (I);
Max_Value := Working_Table (I, Cap);
Count := 0;
Weight := 0;
for J in 1 .. Candidates (I).Count loop
W := Item_Weight (J) * Answer (I).Weight;
V := Item_Value (J) * Answer (I).Value;
if W <= Cap and then
Max_Value = Working_Table (I - 1, Cap - W) + V then
Weight := W;
Count := J;
end if;
end loop;
Cap := Cap - Weight;
Answer (I).Count := Count;
end loop;
end Trace_Answer;
procedure Show_Answer is
package Count_IO is new Ada.Text_IO.Integer_IO (Item_Count);
package Weight_IO is new Ada.Text_IO.Integer_IO (Item_Weight);
package Value_IO is new Ada.Text_IO.Integer_IO (Item_Value);
Item : Item_Pool;
C, Total_Items : Item_Count := 0;
W, Total_Weight : Item_Weight := 0;
V, Total_Value : Item_Value := 0;
Totals : String (Item_Name'Range) := "Totals ";
begin
for I in Answer'Range loop
Item := Answer (I);
C := Item.Count;
W := Item.Weight * Item_Weight (Item.Count);
V := Item.Value * Item_Value (Item.Count);
Total_Items := Total_Items + Item.Count;
Total_Weight := Total_Weight + W;
Total_Value := Total_Value + V;
if C > 0 then
Ada.Text_IO.Put (Item.Name);
Count_IO.Put (C);
Weight_IO.Put (W);
Value_IO.Put (V);
Ada.Text_IO.New_Line;
end if;
end loop;
Ada.Text_IO.Put (Totals);
Count_IO.Put (Total_Items);
Weight_IO.Put (Total_Weight);
Value_IO.Put (Total_Value);
Ada.Text_IO.New_Line;
end Show_Answer;
begin
Fill_Table;
Trace_Answer;
Show_Answer;
end Knapsack_Bounded;

View file

@ -3,32 +3,32 @@
(defun knapsack (max-weight items)
(let ((cache (make-array (list (1+ max-weight) (1+ (length items)))
:initial-element nil)))
:initial-element nil)))
(labels ((knapsack1 (spc items)
(if (not items) (return-from knapsack1 (list 0 0 '())))
(mm-set (aref cache spc (length items))
(let* ((i (first items))
(w (second i))
(v (third i))
(x (knapsack1 spc (cdr items))))
(loop for cnt from 1 to (fourth i) do
(let ((w (* cnt w)) (v (* cnt v)))
(if (>= spc w)
(let ((y (knapsack1 (- spc w) (cdr items))))
(if (> (+ (first y) v) (first x))
(setf x (list (+ (first y) v)
(+ (second y) w)
(cons (list (first i) cnt) (third y)))))))))
x))))
(if (not items) (return-from knapsack1 (list 0 0 '())))
(mm-set (aref cache spc (length items))
(let* ((i (first items))
(w (second i))
(v (third i))
(x (knapsack1 spc (cdr items))))
(loop for cnt from 1 to (fourth i) do
(let ((w (* cnt w)) (v (* cnt v)))
(if (>= spc w)
(let ((y (knapsack1 (- spc w) (cdr items))))
(if (> (+ (first y) v) (first x))
(setf x (list (+ (first y) v)
(+ (second y) w)
(cons (list (first i) cnt) (third y)))))))))
x))))
(knapsack1 max-weight items))))
(print
(knapsack 400
'((map 9 150 1) (compass 13 35 1) (water 153 200 2) (sandwich 50 60 2)
'((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) (cream 11 70 1) (camera 32 30 1)
(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))))
(cheese 23 30 1) (beer 52 10 3) (cream 11 70 1) (camera 32 30 1)
(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))))

View file

@ -12,17 +12,17 @@
;; into vector of repeated indices : [1 2 3 4 4 4 5 5 6 ... ]
(define (make-01 T)
(for ((record T) (i (in-naturals)))
(for ((j (in-range 0 (goodies-qty record))))
(vector-push IDX i)))
IDX)
(for ((record T) (i (in-naturals)))
(for ((j (in-range 0 (goodies-qty record))))
(vector-push IDX i)))
IDX)
(define-syntax-rule (name i) (table-xref T (vector-ref IDX i) 0))
(define-syntax-rule (poids i) (table-xref T (vector-ref IDX i) 1))
(define-syntax-rule (valeur i) (table-xref T (vector-ref IDX i) 2))
;;
;; code identical to 0/1 problem
;; code identical to 0/1 problem
;;
;; make an unique hash-key from (i rest)
@ -32,23 +32,23 @@
;; compute best score (i), assuming best (i-1 rest) is known
(define (score i restant)
(if (< i 0) 0
(hash-ref! H (t-idx i restant)
(if ( >= restant (poids i))
(max
(score (1- i) restant)
(+ (score (1- i) (- restant (poids i))) (valeur i)))
(score (1- i) restant)) ;; else not enough
)))
(if (< i 0) 0
(hash-ref! H (t-idx i restant)
(if ( >= restant (poids i))
(max
(score (1- i) restant)
(+ (score (1- i) (- restant (poids i))) (valeur i)))
(score (1- i) restant)) ;; else not enough
)))
;; compute best scores, starting from last item
(define (task W)
(define restant W)
(make-01 T)
(define N (1- (vector-length IDX)))
(writeln 'total-value (score N W))
(group
(for/list ((i (in-range N -1 -1)))
#:continue (= (t-get i restant) (t-get (1- i) restant))
(set! restant (- restant (poids i)))
(name i))))
(writeln 'total-value (score N W))
(group
(for/list ((i (in-range N -1 -1)))
#:continue (= (t-get i restant) (t-get (1- i) restant))
(set! restant (- restant (poids i)))
(name i))))

View file

@ -0,0 +1,146 @@
// Item name, weight, value, piece(s)
i = [ ["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]]
[maxvalue, maxweight, usedDict] = knapsackBounded[i.getColumn[2], // value
i.getColumn[1], // weight
i.getColumn[3], // count
400]
res = new array
for ind = sort[keys[usedDict]]
res.push[ [" ", i@ind@0 , ":", usedDict@ind] ]
println["Items:"]
println[formatTable[res, "right"]]
println[]
println["Total weight: $maxweight"]
println["Total value: $maxvalue"]
knapsack[values, weights, capacity] :=
{
n = length[values]
if length[weights] != n
{
println["knapsack: length of values does not equal length of weights."]
return undef
}
V = new array[[n+1, capacity+1], 0]
keep = new array[[n+1, capacity+1], false]
for i = 1 to n
{
for w = 0 to capacity
{
if weights@(i-1) <= w and (values@(i-1) + V@(i-1)@(w - weights@(i-1)) > V@(i-1)@w)
{
V@i@w = values@(i-1) + V@(i-1)@(w-weights@(i-1))
keep@i@w = true
} else
{
V@i@w = V@(i-1)@w
keep@i@w = false
}
}
}
included = new array
K = capacity
for i = n to 1 step -1
if keep@i@K == true
{
included.push[ [i-1, values@(i-1), weights@(i-1)] ]
K = K - weights@(i-1)
}
return concat[V@n@capacity, included.transpose[]]
}
knapsackBounded[values, weights, maxcount, capacity] :=
{
len = length[values]
if length[weights] != len or length[maxcount] != len
{
println["knapsackBounded: length of values or counts does not equal length of weights."]
return undef
}
values1 = new array
weights1 = new array
multipliers = new array // Array of [origIndex, multiplier]
ITEM:
for i = 0 to len-1
{
count = maxcount@i
if count == 1
{
values1.push[values@i]
weights1.push[weights@i]
multipliers.push[ [i, 1] ]
}
if count > 1
{
nsum = 1
multiplier = 1
do
{
// Create multiples of 1,2,4,8... of the items
values1.push[values@i * multiplier]
weights1.push[weights@i * multiplier]
multipliers.push[ [i, multiplier] ]
multiplier = multiplier * 2
nsum = nsum + multiplier
} while nsum < count
nsum = nsum - multiplier
multiplier = multiplier / 2
// We have leftovers; add one more multiple to use them all
if nsum < count
{
diff = count - nsum
values1.push[values@i * diff]
weights1.push[weights@i * diff]
multipliers.push[ [i, diff] ]
}
}
}
[maxvalue2, indices2, values2, weights2] = knapsack[values1, weights1, capacity]
used = new dict // Dictionary of <origIndex, times>
for idx = indices2
{
// Map multiples back to a count of originals
[origIndex, times] = multipliers@idx
used.increment[origIndex, times]
}
return [maxvalue2, sum[weights2], used]
}

View file

@ -3,97 +3,97 @@ package main
import "fmt"
type Item struct {
name string
weight, value, qty int
name string
weight, value, qty int
}
var items = []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},
{"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-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},
{"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},
{"w-trousers", 42, 70, 1},
{"w-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 Chooser struct {
Items []Item
cache map[key]solution
Items []Item
cache map[key]solution
}
type key struct {
w, p int
w, p int
}
type solution struct {
v, w int
qty []int
v, w int
qty []int
}
func (c Chooser) Choose(limit int) (w, v int, qty []int) {
c.cache = make(map[key]solution)
s := c.rchoose(limit, len(c.Items)-1)
c.cache = nil // allow cache to be garbage collected
return s.v, s.w, s.qty
c.cache = make(map[key]solution)
s := c.rchoose(limit, len(c.Items)-1)
c.cache = nil // allow cache to be garbage collected
return s.v, s.w, s.qty
}
func (c Chooser) rchoose(limit, pos int) solution {
if pos < 0 || limit <= 0 {
return solution{0, 0, nil}
}
if pos < 0 || limit <= 0 {
return solution{0, 0, nil}
}
key := key{limit, pos}
if s, ok := c.cache[key]; ok {
return s
}
key := key{limit, pos}
if s, ok := c.cache[key]; ok {
return s
}
best_i, best := 0, solution{0, 0, nil}
for i := 0; i*items[pos].weight <= limit && i <= items[pos].qty; i++ {
sol := c.rchoose(limit-i*items[pos].weight, pos-1)
sol.v += i * items[pos].value
if sol.v > best.v {
best_i, best = i, sol
}
}
best_i, best := 0, solution{0, 0, nil}
for i := 0; i*items[pos].weight <= limit && i <= items[pos].qty; i++ {
sol := c.rchoose(limit-i*items[pos].weight, pos-1)
sol.v += i * items[pos].value
if sol.v > best.v {
best_i, best = i, sol
}
}
if best_i > 0 {
// best.qty is used in another cache entry,
// we need to duplicate it before modifying it to
// store as our cache entry.
old := best.qty
best.qty = make([]int, len(items))
copy(best.qty, old)
best.qty[pos] = best_i
best.w += best_i * items[pos].weight
}
c.cache[key] = best
return best
if best_i > 0 {
// best.qty is used in another cache entry,
// we need to duplicate it before modifying it to
// store as our cache entry.
old := best.qty
best.qty = make([]int, len(items))
copy(best.qty, old)
best.qty[pos] = best_i
best.w += best_i * items[pos].weight
}
c.cache[key] = best
return best
}
func main() {
v, w, s := Chooser{Items: items}.Choose(400)
v, w, s := Chooser{Items: items}.Choose(400)
fmt.Println("Taking:")
for i, t := range s {
if t > 0 {
fmt.Printf(" %d of %d %s\n", t, items[i].qty, items[i].name)
}
}
fmt.Printf("Value: %d; weight: %d\n", v, w)
fmt.Println("Taking:")
for i, t := range s {
if t > 0 {
fmt.Printf(" %d of %d %s\n", t, items[i].qty, items[i].name)
}
}
fmt.Printf("Value: %d; weight: %d\n", v, w)
}

View file

@ -1,15 +1,15 @@
inv = [("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), ("cream",11,70,1), ("camera",32,30,1),
-- what to do if we end up taking one trouser?
("tshirt",24,15,2), ("trousers",48,10,2), ("umbrella",73,40,1), ("wtrousers",42,70,1),
("woverclothes",43,75,1), ("notecase",22,80,1), ("sunglasses",7,20,1), ("towel",18,12,2),
("socks",4,50,1), ("book",30,10,2)]
inv = [("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), ("cream",11,70,1), ("camera",32,30,1),
-- what to do if we end up taking one trouser?
("tshirt",24,15,2), ("trousers",48,10,2), ("umbrella",73,40,1), ("wtrousers",42,70,1),
("woverclothes",43,75,1), ("notecase",22,80,1), ("sunglasses",7,20,1), ("towel",18,12,2),
("socks",4,50,1), ("book",30,10,2)]
knapsack = foldr addItem (repeat (0,[])) where
addItem (name,w,v,c) old = foldr inc old [1..c] where
inc i list = left ++ zipWith max right new where
(left, right) = splitAt (w * i) list
new = map (\(val,itms)->(val + v * i, (name,i):itms)) old
addItem (name,w,v,c) old = foldr inc old [1..c] where
inc i list = left ++ zipWith max right new where
(left, right) = splitAt (w * i) list
new = map (\(val,itms)->(val + v * i, (name,i):itms)) old
main = print $ (knapsack inv) !! 400

View file

@ -2,10 +2,10 @@ import Data.Array
-- snipped the item list; use the one from above
knapsack items cap = (solu items) ! cap where
solu = foldr f (listArray (0,cap) (repeat (0,[])))
f (name,w,v,cnt) ss = listArray (0,cap) $ map optimal [0..] where
optimal ww = maximum $ (ss!ww):[prepend (v*i,(name,i)) (ss!(ww - i*w))
| i <- [1..cnt], i*w < ww]
prepend (x,n) (y,s) = (x+y,n:s)
solu = foldr f (listArray (0,cap) (repeat (0,[])))
f (name,w,v,cnt) ss = listArray (0,cap) $ map optimal [0..] where
optimal ww = maximum $ (ss!ww):[prepend (v*i,(name,i)) (ss!(ww - i*w))
| i <- [1..cnt], i*w < ww]
prepend (x,n) (y,s) = (x+y,n:s)
main = do print $ knapsack inv 400

View file

@ -27,53 +27,53 @@ var data= [
];
function findBestPack() {
var m= [[0]]; // maximum pack value found so far
var b= [[0]]; // best combination found so far
var opts= [0]; // item index for 0 of item 0
var P= [1]; // item encoding for 0 of item 0
var choose= 0;
for (var j= 0; j<data.length; j++) {
opts[j+1]= opts[j]+data[j].pieces; // item index for 0 of item j+1
P[j+1]= P[j]*(1+data[j].pieces); // item encoding for 0 of item j+1
}
for (var j= 0; j<opts[data.length]; j++) {
m[0][j+1]= b[0][j+1]= 0; // best values and combos for empty pack: nothing
}
for (var w=1; w<=400; w++) {
m[w]= [0];
b[w]= [0];
for (var j=0; j<data.length; j++) {
var N= data[j].pieces; // how many of these can we have?
var base= opts[j]; // what is the item index for 0 of these?
for (var n= 1; n<=N; n++) {
var W= n*data[j].weight; // how much do these items weigh?
var s= w>=W ?1 :0; // can we carry this many?
var v= s*n*data[j].value; // how much are they worth?
var I= base+n; // what is the item number for this many?
var wN= w-s*W; // how much other stuff can we be carrying?
var C= n*P[j] + b[wN][base]; // encoded combination
m[w][I]= Math.max(m[w][I-1], v+m[wN][base]); // best value
choose= b[w][I]= m[w][I]>m[w][I-1] ?C :b[w][I-1];
}
}
}
var best= [];
for (var j= data.length-1; j>=0; j--) {
best[j]= Math.floor(choose/P[j]);
choose-= best[j]*P[j];
}
var out='<table><tr><td><b>Count</b></td><td><b>Item</b></td><th>unit weight</th><th>unit value</th>';
var wgt= 0;
var val= 0;
for (var i= 0; i<best.length; i++) {
if (0==best[i]) continue;
out+='</tr><tr><td>'+best[i]+'</td><td>'+data[i].name+'</td><td>'+data[i].weight+'</td><td>'+data[i].value+'</td>'
wgt+= best[i]*data[i].weight;
val+= best[i]*data[i].value;
}
out+= '</tr></table><br/>Total weight: '+wgt;
out+= '<br/>Total value: '+val;
document.body.innerHTML= out;
var m= [[0]]; // maximum pack value found so far
var b= [[0]]; // best combination found so far
var opts= [0]; // item index for 0 of item 0
var P= [1]; // item encoding for 0 of item 0
var choose= 0;
for (var j= 0; j<data.length; j++) {
opts[j+1]= opts[j]+data[j].pieces; // item index for 0 of item j+1
P[j+1]= P[j]*(1+data[j].pieces); // item encoding for 0 of item j+1
}
for (var j= 0; j<opts[data.length]; j++) {
m[0][j+1]= b[0][j+1]= 0; // best values and combos for empty pack: nothing
}
for (var w=1; w<=400; w++) {
m[w]= [0];
b[w]= [0];
for (var j=0; j<data.length; j++) {
var N= data[j].pieces; // how many of these can we have?
var base= opts[j]; // what is the item index for 0 of these?
for (var n= 1; n<=N; n++) {
var W= n*data[j].weight; // how much do these items weigh?
var s= w>=W ?1 :0; // can we carry this many?
var v= s*n*data[j].value; // how much are they worth?
var I= base+n; // what is the item number for this many?
var wN= w-s*W; // how much other stuff can we be carrying?
var C= n*P[j] + b[wN][base]; // encoded combination
m[w][I]= Math.max(m[w][I-1], v+m[wN][base]); // best value
choose= b[w][I]= m[w][I]>m[w][I-1] ?C :b[w][I-1];
}
}
}
var best= [];
for (var j= data.length-1; j>=0; j--) {
best[j]= Math.floor(choose/P[j]);
choose-= best[j]*P[j];
}
var out='<table><tr><td><b>Count</b></td><td><b>Item</b></td><th>unit weight</th><th>unit value</th>';
var wgt= 0;
var val= 0;
for (var i= 0; i<best.length; i++) {
if (0==best[i]) continue;
out+='</tr><tr><td>'+best[i]+'</td><td>'+data[i].name+'</td><td>'+data[i].weight+'</td><td>'+data[i].value+'</td>'
wgt+= best[i]*data[i].weight;
val+= best[i]*data[i].value;
}
out+= '</tr></table><br/>Total weight: '+wgt;
out+= '<br/>Total value: '+val;
document.body.innerHTML= out;
}
findBestPack();
</script>

View file

@ -34,14 +34,14 @@ def knapsack($w):
| reduce range(1; $n+1) as $i (.;
reduce range (0; $w + 1) as $j (.;
.m[$i][$j] = .m[$i-1][$j]
| label $out
| 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
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)
end;
if .stop or ($k == null) then ., break $out else empty end)
) )
| .s = ($n|list(0))
| .j = $w
@ -78,9 +78,9 @@ def task(maxWeight):
| .sumNumber += .number
| .sumWeight += .weight
| .sumValue += .value
| .emit += [[.name, .weight, .value, .number]]
else .
end )
| .emit += [[.name, .weight, .value, .number]]
else .
end )
| (.emit[] | f),
"---------------------- ------ ----- ------",
f("Items chosen \(.itemCount|lpad(4))"; .sumWeight; .sumValue; .sumNumber) );

View file

@ -11,27 +11,27 @@
-- {name weight value quantity wt/val }
items = {
{"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},
{"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},
}
-- for output
@ -55,7 +55,7 @@ function print_as_sack(its)
local name,wt,val,q = table.unpack(it)
local fmt_table =
string.format(data_fmt, name, wt, val, q)
string.format(data_fmt, name, wt, val, q)
io.write(fmt_table, "\n")
end
io.write(line, "\n")
@ -99,19 +99,19 @@ function add_up (its, max, excl)
local count = 0
local w = 0
for j = 1, q do
local t_wt = wt +this_weight
if t_wt < max then
this_value = this_value + val
this_weight = t_wt
count = count + 1
end
local t_wt = wt +this_weight
if t_wt < max then
this_value = this_value + val
this_weight = t_wt
count = count + 1
end
end
if this_weight >= max then break end
if count > 0 then
_s = {name, count}
table.insert (sack, _s)
_s = {name, count}
table.insert (sack, _s)
end
::continue:: --skip item, continue
@ -120,24 +120,24 @@ function add_up (its, max, excl)
-- go through chosen sack
-- make sack of items
for s = 1,#sack do
local s_item = sack[s]
local s_name,s_count = table.unpack(s_item)
local s_item = sack[s]
local s_name,s_count = table.unpack(s_item)
for j = 1,#its do
local it = its[j]
local iname = it[1]
if iname == s_name then
it[4] = s_count
table.insert(sack_items, it)
end -- if
end -- for j
for j = 1,#its do
local it = its[j]
local iname = it[1]
if iname == s_name then
it[4] = s_count
table.insert(sack_items, it)
end -- if
end -- for j
end -- for sack
-- update best
if this_value > best_value then
best_value = this_value
best_weight = this_weight
best_sack = sack_items
best_value = this_value
best_weight = this_weight
best_sack = sack_items
end
end -- function add_up

View file

@ -19,28 +19,28 @@ maximize knap_value: sum{t in Items} take[t] * value[t];
data;
param : Items : weight value quantity :=
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
w-trousers 42 70 1
w-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
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
w-trousers 42 70 1
w-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
;
end;

View file

@ -7,7 +7,7 @@ sys items=22
it=>
"map", 9, 150, 0,
"map", 9, 150, 0,
"compass", 13, 35, 0,
"water", 153, 200, 0,
"sandwich", 50, 160, 0,
@ -94,17 +94,17 @@ pr+=cr "Weight: " dmax+xs
'putfile "s.txt",pr
print pr
'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
'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
'
'Weight: 396

View file

@ -60,7 +60,7 @@ in
{Record.forAllInd Best
proc {$ I V}
if V > 0 then
{System.showInfo I#": "#V}
{System.showInfo I#": "#V}
end
end
}

View file

@ -3,71 +3,71 @@
use strict;
my $raw = <<'TABLE';
map 9 150 1
compass 13 35 1
water 153 200 2
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
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
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
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
towel 18 12 2
socks 4 50 1
book 30 10 2
TABLE
my @items;
for (split "\n", $raw) {
my @x = split /\s+/;
push @items, {
name => $x[0],
weight => $x[1],
value => $x[2],
quant => $x[3],
}
push @items, {
name => $x[0],
weight => $x[1],
value => $x[2],
quant => $x[3],
}
}
my $max_weight = 400;
my %cache;
sub pick {
my ($weight, $pos) = @_;
if ($pos < 0 or $weight <= 0) {
return 0, 0, []
}
my ($weight, $pos) = @_;
if ($pos < 0 or $weight <= 0) {
return 0, 0, []
}
@{ $cache{$weight, $pos} //= [do{ # odd construct: for caching
my $item = $items[$pos];
my ($bv, $bi, $bw, $bp) = (0, 0, 0, []);
@{ $cache{$weight, $pos} //= [do{ # odd construct: for caching
my $item = $items[$pos];
my ($bv, $bi, $bw, $bp) = (0, 0, 0, []);
for my $i (0 .. $item->{quant}) {
last if $i * $item->{weight} > $weight;
my ($v, $w, $p) = pick($weight - $i * $item->{weight}, $pos - 1);
next if ($v += $i * $item->{value}) <= $bv;
for my $i (0 .. $item->{quant}) {
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);
}
($bv, $bi, $bw, $bp) = ($v, $i, $w, $p);
}
my @picked = ( @$bp, $bi );
$bv, $bw + $bi * $item->{weight}, \@picked
}]}
my @picked = ( @$bp, $bi );
$bv, $bw + $bi * $item->{weight}, \@picked
}]}
}
my ($v, $w, $p) = pick($max_weight, $#items);
for (0 .. $#$p) {
if ($p->[$_] > 0) {
print "$p->[$_] of $items[$_]{name}\n";
}
if ($p->[$_] > 0) {
print "$p->[$_] of $items[$_]{name}\n";
}
}
print "Value: $v; Weight: $w\n";

View file

@ -0,0 +1,85 @@
require "table2"
local fmt = require "fmt"
class item
function __construct(public name, public weight, public value, public count)
end
end
local items = {
new item("map", 9, 150, 1),
new item("compass", 13, 35, 1),
new item("water", 153, 200, 2),
new item("sandwich", 50, 60, 2),
new item("glucose", 15, 60, 2),
new item("tin", 68, 45, 3),
new item("banana", 27, 60, 3),
new item("apple", 39, 40, 3),
new item("cheese", 23, 30, 1),
new item("beer", 52, 10, 3),
new item("suntan cream", 11, 70, 1),
new item("camera", 32, 30, 1),
new item("T-shirt", 24, 15, 2),
new item("trousers", 48, 10, 2),
new item("umbrella", 73, 40, 1),
new item("waterproof trousers", 42, 70, 1),
new item("waterproof overclothes", 43, 75, 1),
new item("note-case", 22, 80, 1),
new item("sunglasses", 7, 20, 1),
new item("towel", 18, 12, 2),
new item("socks", 4, 50, 1),
new item("book", 30, 10, 2)
}
local n = #items
local max_weight = 400
local function knapsack(w)
local m = table.create(n + 1)
for i = 0, n do m[i + 1] = table.rep(w + 1, 0) end
for i = 1, n do
for j = 0, w do
m[i + 1][j + 1] = m[i][j + 1]
for k = 1, items[i].count do
if k * items[i].weight > j then break end
local v = m[i][j - k * items[i].weight + 1] + k * items[i].value
if v > m[i + 1][j + 1] then m[i + 1][j + 1] = v end
end
end
end
local s = table.rep(n, 0)
local j = w
for i = n, 1, -1 do
local v = m[i + 1][j + 1]
local k = 0
while v != m[i][j + 1] + k * items[i].value do
s[i] += 1
j -= items[i].weight
k += 1
end
end
return s
end
local s = knapsack(max_weight)
print("Item Chosen Weight Value Number")
print("--------------------- ------ ----- ------")
local item_count = 0
local sum_weight = 0
local sum_value = 0
local sum_number = 0
for i = 1, n do
if s[i] != 0 then
item_count += 1
local name = items[i].name
local number = s[i]
local weight = items[i].weight * number
local value = items[i].value * number
sum_number += number
sum_weight += weight
sum_value += value
fmt.print("%-22s %3d %4d %2d", name, weight, value, number)
end
end
print("--------------------- ------ ----- ------")
fmt.print("Items chosen %d %3d %4d %2d", item_count, sum_weight, sum_value, sum_number)

View file

@ -2,75 +2,75 @@
% tuples (name, weights, value, nb pieces).
knapsack :-
L = [( 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)],
L = [( 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)],
% Takes is the list of the numbers of each items
% these numbers are between 0 and the 4th value of the tuples of the items
% Takes is the list of the numbers of each items
% these numbers are between 0 and the 4th value of the tuples of the items
maplist(collect, L, Ws, Vs, Takes),
scalar_product(Ws, Takes, #=<, 400),
scalar_product(Vs, Takes, #=, VM),
% to have statistics on the resolution of the problem.
time(labeling([max(VM), down], Takes)),
% to have statistics on the resolution of the problem.
time(labeling([max(VM), down], Takes)),
scalar_product(Ws, Takes, #=, WM),
%% displayinf of the results.
compute_lenword(L, 0, Len),
sformat(A1, '~~w~~t~~~w|', [Len]),
sformat(A2, '~~t~~w~~~w|', [4]),
sformat(A3, '~~t~~w~~~w|', [5]),
print_results(A1,A2,A3, L, Takes, WM, VM).
%% displayinf of the results.
compute_lenword(L, 0, Len),
sformat(A1, '~~w~~t~~~w|', [Len]),
sformat(A2, '~~t~~w~~~w|', [4]),
sformat(A3, '~~t~~w~~~w|', [5]),
print_results(A1,A2,A3, L, Takes, WM, VM).
collect((_, W, V, N), W, V, Take) :-
Take in 0..N.
Take in 0..N.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
compute_lenword([], N, N).
compute_lenword([(Name, _, _, _)|T], N, NF):-
atom_length(Name, L),
( L > N -> N1 = L; N1 = N),
compute_lenword(T, N1, NF).
atom_length(Name, L),
( L > N -> N1 = L; N1 = N),
compute_lenword(T, N1, NF).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
print_results(A1,A2,A3, [], [], WM, WR) :-
sformat(W0, '~w ', [' ']),
sformat(W1, A1, [' ']),
sformat(W2, A2, [WM]),
sformat(W3, A3, [WR]),
format('~w~w~w~w~n', [W0,W1,W2,W3]).
sformat(W0, '~w ', [' ']),
sformat(W1, A1, [' ']),
sformat(W2, A2, [WM]),
sformat(W3, A3, [WR]),
format('~w~w~w~w~n', [W0,W1,W2,W3]).
print_results(A1,A2,A3, [_H|T], [0|TR], WM, VM) :-
!,
print_results(A1,A2,A3, T, TR, WM, VM).
!,
print_results(A1,A2,A3, T, TR, WM, VM).
print_results(A1, A2, A3, [(Name, W, V, _)|T], [N|TR], WM, VM) :-
sformat(W0, '~w ', [N]),
sformat(W1, A1, [Name]),
sformat(W2, A2, [W]),
sformat(W3, A3, [V]),
format('~w~w~w~w~n', [W0,W1,W2,W3]),
print_results(A1, A2, A3, T, TR, WM, VM).
sformat(W0, '~w ', [N]),
sformat(W1, A1, [Name]),
sformat(W2, A2, [W]),
sformat(W3, A3, [V]),
format('~w~w~w~w~n', [W0,W1,W2,W3]),
print_results(A1, A2, A3, T, TR, WM, VM).

View file

@ -1,51 +1,51 @@
:- use_module(library(simplex)).
% tuples (name, weights, value, pieces).
knapsack :-
L = [(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)],
L = [(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)],
gen_state(S0),
length(L, N),
numlist(1, N, LN),
time(( create_constraint_N(LN, L, S0, S1),
maplist(create_constraint_WV, LN, L, LW, LV),
constraint(LW =< 400, S1, S2),
maximize(LV, S2, S3)
)),
compute_lenword(L, 0, Len),
sformat(A1, '~~w~~t~~~w|', [Len]),
sformat(A2, '~~t~~w~~~w|', [4]),
sformat(A3, '~~t~~w~~~w|', [5]),
print_results(S3, A1,A2,A3, L, LN, 0, 0).
gen_state(S0),
length(L, N),
numlist(1, N, LN),
time(( create_constraint_N(LN, L, S0, S1),
maplist(create_constraint_WV, LN, L, LW, LV),
constraint(LW =< 400, S1, S2),
maximize(LV, S2, S3)
)),
compute_lenword(L, 0, Len),
sformat(A1, '~~w~~t~~~w|', [Len]),
sformat(A2, '~~t~~w~~~w|', [4]),
sformat(A3, '~~t~~w~~~w|', [5]),
print_results(S3, A1,A2,A3, L, LN, 0, 0).
create_constraint_N([], [], S, S).
create_constraint_N([HN|TN], [(_, _, _, Nb) | TL], S1, SF) :-
constraint(integral(x(HN)), S1, S2),
constraint([x(HN)] =< Nb, S2, S3),
constraint([x(HN)] >= 0, S3, S4),
create_constraint_N(TN, TL, S4, SF).
constraint(integral(x(HN)), S1, S2),
constraint([x(HN)] =< Nb, S2, S3),
constraint([x(HN)] >= 0, S3, S4),
create_constraint_N(TN, TL, S4, SF).
create_constraint_WV(N, (_, W, V, _), W * x(N), V * x(N)).
@ -53,28 +53,28 @@ create_constraint_WV(N, (_, W, V, _), W * x(N), V * x(N)).
%
compute_lenword([], N, N).
compute_lenword([(Name, _, _, _)|T], N, NF):-
atom_length(Name, L),
( L > N -> N1 = L; N1 = N),
compute_lenword(T, N1, NF).
atom_length(Name, L),
( L > N -> N1 = L; N1 = N),
compute_lenword(T, N1, NF).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
print_results(_S, A1, A2, A3, [], [], WM, VM) :-
sformat(W0, '~w ', [' ']),
sformat(W1, A1, [' ']),
sformat(W2, A2, [WM]),
sformat(W3, A3, [VM]),
format('~w~w~w~w~n', [W0, W1,W2,W3]).
sformat(W0, '~w ', [' ']),
sformat(W1, A1, [' ']),
sformat(W2, A2, [WM]),
sformat(W3, A3, [VM]),
format('~w~w~w~w~n', [W0, W1,W2,W3]).
print_results(S, A1, A2, A3, [(Name, W, V,_)|T], [N|TN], W1, V1) :-
variable_value(S, x(N), X),
( X = 0 -> W1 = W2, V1 = V2
; sformat(S0, '~w ', [X]),
sformat(S1, A1, [Name]),
sformat(S2, A2, [W]),
sformat(S3, A3, [V]),
format('~w~w~w~w~n', [S0, S1,S2,S3]),
W2 is W1 + X * W,
V2 is V1 + X * V),
print_results(S, A1, A2, A3, T, TN, W2, V2).
variable_value(S, x(N), X),
( X = 0 -> W1 = W2, V1 = V2
; sformat(S0, '~w ', [X]),
sformat(S1, A1, [Name]),
sformat(S2, A2, [W]),
sformat(S3, A3, [V]),
format('~w~w~w~w~n', [S0, S1,S2,S3]),
W2 is W1 + X * W,
V2 is V1 + X * V),
print_results(S, A1, A2, A3, T, TN, W2, V2).

View file

@ -1,26 +1,26 @@
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),
"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),
}
item_keys = list(items.keys())

View file

@ -0,0 +1,112 @@
Rebol [
title: "Rosetta code: Knapsack problem/Bounded"
file: %Knapsack_problem-Bounded.r3
url: https://rosettacode.org/wiki/Knapsack_problem/Bounded
]
solve-knapsack: function/with [
"Solves the bounded knapsack problem via top-down dynamic programming."
limit [integer!] "remaining weight capacity"
pos [integer!] "current item index (0-based)"
][
;; Returns a 3-element block [value weight taken] where `taken` is a
;; block of per-item counts (parallel to `items`) representing the
;; optimal selection, or none if nothing fits.
;; Results are memoised in `cache` keyed by "limit,pos" so each
;; sub-problem is solved at most once.
if any [pos < 0 limit <= 0] [ ;; base case: no items or no capacity
return reduce [0 0 none]
]
key-str: rejoin [limit "," pos]
if cached: cache/:key-str [ return cached ] ;; memoisation hit
item: items/(pos + 1) ;; [name weight value max-qty]
best-value: 0
best-weight: 0
best-count: 0
best-taken: none
taken: 0
while [all [taken * item/2 <= limit taken <= item/4]] [ ;; try 0..max-qty copies
sub: solve-knapsack (limit - (taken * item/2)) (pos - 1) ;; best for remaining items
sub-value: sub/1
sub-weight: sub/2
sub-taken: sub/3
candidate-value: sub-value + (taken * item/3)
if candidate-value > best-value [ ;; keep best combination found so far
best-value: candidate-value
best-weight: sub-weight
best-count: taken
best-taken: sub-taken
]
++ taken
]
if best-count > 0 [
new-taken: make block! num-items ;; copy before mutating to avoid aliasing cached entries
repeat k num-items [append new-taken 0]
if block? best-taken [
repeat k num-items [new-taken/:k: best-taken/:k]
]
new-taken/(pos + 1): best-count ;; record how many of this item we take
best-weight: best-weight + (best-count * item/2)
best-taken: new-taken
]
result: reduce [best-value best-weight best-taken]
cache/(key-str): result ;; store [value weight taken-counts] in memo
result
][
cache: make map! 2000 ;; memoisation table, shared across calls
]
items: [
["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]
["w-trousers" 42 70 1]
["w-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]
]
item-name: func [item] [item/1]
item-weight: func [item] [item/2]
item-value: func [item] [item/3]
item-limit: func [item] [item/4]
num-items: length? items
result: solve-knapsack 400 (num-items - 1)
total-value: result/1
total-weight: result/2
taken: result/3
print "Taking:"
if block? taken [
repeat i num-items [
count: pick taken i
if count > 0 [
item: pick items i
print [" " count "of" item-limit item " " item-name item]
]
]
]
print ajoin ["Value: " total-value "; weight: " total-weight]

View file

@ -1,48 +1,48 @@
# The list of items to consider, as list of lists
set items {
{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}
{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}
}
# Simple extraction functions
proc countednames {chosen} {
set names {}
foreach item $chosen {
lappend names [lindex $item 3] [lindex $item 0]
lappend names [lindex $item 3] [lindex $item 0]
}
return $names
}
proc weight {chosen} {
set weight 0
foreach item $chosen {
incr weight [expr {[lindex $item 3] * [lindex $item 1]}]
incr weight [expr {[lindex $item 3] * [lindex $item 1]}]
}
return $weight
}
proc value {chosen} {
set value 0
foreach item $chosen {
incr value [expr {[lindex $item 3] * [lindex $item 2]}]
incr value [expr {[lindex $item 3] * [lindex $item 2]}]
}
return $value
}
@ -51,26 +51,26 @@ proc value {chosen} {
proc knapsackSearch {items {chosen {}}} {
# If we've gone over the weight limit, stop now
if {[weight $chosen] > 400} {
return
return
}
# If we've considered all of the items (i.e., leaf in search tree)
# then see if we've got a new best choice.
if {[llength $items] == 0} {
global best max
set v [value $chosen]
if {$v > $max} {
set max $v
set best $chosen
}
return
global best max
set v [value $chosen]
if {$v > $max} {
set max $v
set best $chosen
}
return
}
# Branch, so recurse for chosing the current item or not
set this [lindex $items 0]
set rest [lrange $items 1 end]
knapsackSearch $rest $chosen
for {set i 1} {$i<=[lindex $this 3]} {incr i} {
knapsackSearch $rest \
[concat $chosen [list [lreplace $this end end $i]]]
knapsackSearch $rest \
[concat $chosen [list [lreplace $this end end $i]]]
}
}

View file

@ -3,6 +3,6 @@ fcn addItem(old,[(nm,w,v,c)]){ // old:list:(cost of:,(name,#,...))
wi,left,right:=w*i,list[0,wi],list[wi,*];
new:=old.apply('wrap([(val,itms)]){ T(val + v*i,itms.append(nm,i)) });
left.extend(right.zipWith( // inc
fcn([(v1,_)]a,[(v2,_)]b){ v1>v2 and a or b },new));
fcn([(v1,_)]a,[(v2,_)]b){ v1>v2 and a or b },new));
},old,nm,w,v,old);
}//--> new list