Data update
This commit is contained in:
parent
4bb20c9b71
commit
cbaf4c4b64
12390 changed files with 318560 additions and 27248 deletions
143
Task/Knapsack-problem-Bounded/Ada/knapsack-problem-bounded.adb
Normal file
143
Task/Knapsack-problem-Bounded/Ada/knapsack-problem-bounded.adb
Normal 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;
|
||||
|
|
@ -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))))
|
||||
|
|
|
|||
|
|
@ -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))))
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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) );
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
@ -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]]]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue