This commit is contained in:
Ingy döt Net 2013-04-10 21:29:02 -07:00
parent 764da6cbbb
commit db842d013d
19005 changed files with 197040 additions and 7 deletions

View file

@ -0,0 +1,65 @@
See also: [[Knapsack problem/Bounded]], [[Knapsack problem/0-1]]
A traveller gets diverted and has to make an unscheduled stop in what turns out to be Shangri La. Opting to leave, he is allowed to take as much as he likes of the following items, so long as it will fit in his knapsack, and he can carry it.
He knows that he can carry no more than 25 'weights' in total; and that the capacity of his knapsack is 0.25 'cubic lengths'.
Looking just above the bar codes on the items he finds their weights and volumes. He digs out his recent copy of a financial paper and gets the value of each item.
<table
style="text-align: left; width: 80%;" border="4"
cellpadding="2" cellspacing="2"><tr><td
style="font-weight: bold;" align="left" nowrap="nowrap"
valign="middle">Item</td><td
style="font-weight: bold;" align="left" nowrap="nowrap"
valign="middle">Explanation</td><td
style="font-weight: bold;" align="left" nowrap="nowrap"
valign="middle">Value (each)</td><td
style="font-weight: bold;" align="left" nowrap="nowrap"
valign="middle">weight</td><td
style="font-weight: bold;" align="left" nowrap="nowrap"
valign="middle">Volume (each)</td></tr><tr><td
align="left" nowrap="nowrap" valign="middle">panacea
(vials of)</td><td align="left" nowrap="nowrap"
valign="middle">Incredible healing properties</td><td
align="left" nowrap="nowrap" valign="middle">3000</td><td
align="left" nowrap="nowrap" valign="middle">0.3</td><td
align="left" nowrap="nowrap" valign="middle">0.025</td></tr><tr><td
align="left" nowrap="nowrap" valign="middle">ichor
(ampules of)</td><td align="left" nowrap="nowrap"
valign="middle">Vampires blood</td><td align="left"
nowrap="nowrap" valign="middle">1800</td><td
align="left" nowrap="nowrap" valign="middle">0.2</td><td
align="left" nowrap="nowrap" valign="middle">0.015</td></tr><tr><td
align="left" nowrap="nowrap" valign="middle">gold
(bars)</td><td align="left" nowrap="nowrap"
valign="middle">Shiney shiney</td><td align="left"
nowrap="nowrap" valign="middle">2500</td><td
align="left" nowrap="nowrap" valign="middle">2.0</td><td
align="left" nowrap="nowrap" valign="middle">0.002</td></tr><tr><td
style="background-color: rgb(255, 204, 255);" align="left"
nowrap="nowrap" valign="middle">Knapsack</td><td
style="background-color: rgb(255, 204, 255);" align="left"
nowrap="nowrap" valign="middle">For the carrying of</td><td
style="background-color: rgb(255, 204, 255);" align="left"
nowrap="nowrap" valign="middle">-</td><td
style="background-color: rgb(255, 204, 255);" align="left"
nowrap="nowrap" valign="middle">&lt;=25</td><td
style="background-color: rgb(255, 204, 255);" align="left"
nowrap="nowrap" valign="middle">&lt;=0.25&nbsp;</td></tr></table>
He can only take whole units of any item, but there is much more of any item than he could ever carry
'''How many of each item does he take to maximise the value of items he is carrying away with him?'''
Note:
# There are four solutions that maximise the value taken. Only one ''need'' be given.
<!-- All solutions
# ((value, -weight, -volume), (#panacea, #ichor, #gold)
[((54500, -25.0, -0.24699999999999997), (0, 15, 11)),
((54500, -24.899999999999999, -0.247), (3, 10, 11)),
((54500, -24.800000000000001, -0.24700000000000003), (6, 5, 11)),
((54500, -24.699999999999999, -0.247), (9, 0, 11))]
# (9, 0, 11) also minimizes weight and volume within the limits of calculation
-->

View file

@ -0,0 +1,2 @@
---
note: Classic CS problems and programs

View file

@ -0,0 +1,110 @@
MODE BOUNTY = STRUCT(STRING name, INT value, weight, volume);
[]BOUNTY items = (
("panacea", 3000, 3, 25),
("ichor", 1800, 2, 15),
("gold", 2500, 20, 2)
);
BOUNTY sack := ("sack", 0, 250, 250);
OP * = ([]INT a,b)INT: ( # dot product operator #
INT sum := 0;
FOR i TO UPB a DO sum +:= a[i]*b[i] OD;
sum
);
OP INIT = (REF[]INT vector)VOID:
FOR index FROM LWB vector TO UPB vector DO
vector[index]:=0
OD;
OP INIT = (REF[,]INT matrix)VOID:
FOR row index FROM LWB matrix TO UPB matrix DO
INIT matrix[row index,]
OD;
PROC total value = ([]INT items count, []BOUNTY items, BOUNTY sack) STRUCT(INT value, weight, volume):(
###
Given the count of each item in the sack return -1 if they can"t be carried or their total value.
(also return the negative of the weight and the volume so taking the max of a series of return
values will minimise the weight if values tie, and minimise the volume if values and weights tie).
###
INT weight = items count * weight OF items;
INT volume = items count * volume OF items;
IF weight > weight OF sack OR volume > volume OF sack THEN
(-1, 0, 0)
ELSE
( items count * value OF items, -weight, -volume)
FI
);
PRIO WRAP = 5; # wrap negative array indices as per python's indexing regime #
OP WRAP = (INT index, upb)INT:
IF index>=0 THEN index ELSE upb + index + 1 FI;
PROC knapsack dp = ([]BOUNTY items, BOUNTY sack)[]INT:(
###
Solves the Knapsack problem, with two sets of weights,
using a dynamic programming approach
###
# (weight+1) x (volume+1) table #
# table[w,v] is the maximum value that can be achieved #
# with a sack of weight w and volume v. #
# They all start out as 0 (empty sack) #
[0:weight OF sack, 0:volume OF sack]INT table; INIT table;
FOR w TO 1 UPB table DO
FOR v TO 2 UPB table DO
### Consider the optimal solution, and consider the "last item" added
to the sack. Removing this item must produce an optimal solution
to the subproblem with the sack"s weight and volume reduced by that
of the item. So we search through all possible "last items": ###
FOR item index TO UPB items DO
BOUNTY item := items[item index];
# Only consider items that would fit: #
IF w >= weight OF item AND v >= volume OF item THEN
# Optimal solution to subproblem + value of item: #
INT candidate := table[w-weight OF item,v-volume OF item] + value OF item;
IF candidate > table[w,v] THEN
table[w,v] := candidate
FI
FI
OD
OD
OD;
[UPB items]INT result; INIT result;
INT w := weight OF sack, v := volume OF sack;
WHILE table[w,v] /= 0 DO
# Find the last item that was added: #
INT needle = table[w,v];
INT item index;
FOR i TO UPB items WHILE
item index := i;
BOUNTY item = items[item index];
INT candidate = table[w-weight OF item WRAP UPB table, v-volume OF item WRAP 2 UPB table] + value OF item;
# WHILE # candidate NE needle DO
SKIP
OD;
# Record it in the result, and remove it: #
result[item index] +:= 1;
w -:= weight OF items[item index];
v -:= volume OF items[item index]
OD;
result
);
[]INT max items = knapsack dp(items, sack);
STRUCT (INT value, weight, volume) max := total value(max items, items, sack);
max := (value OF max, -weight OF max, -volume OF max);
FORMAT d = $zz-d$;
printf(($"The maximum value achievable (by dynamic programming) is "gl$, value OF max));
printf(($" The number of ("n(UPB items-1)(g", ")g") items to achieve this is: ("n(UPB items-1)(f(d)",")f(d)") respectively"l$,
name OF items, max items));
printf(($" The weight to carry is "f(d)", and the volume used is "f(d)l$,
weight OF max, volume OF max))

View file

@ -0,0 +1,65 @@
with Ada.Text_IO;
procedure Knapsack_Unbounded is
type Bounty is record
Value : Natural;
Weight : Float;
Volume : Float;
end record;
function Min (A, B : Float) return Float is
begin
if A < B then
return A;
else
return B;
end if;
end Min;
Panacea : Bounty := (3000, 0.3, 0.025);
Ichor : Bounty := (1800, 0.2, 0.015);
Gold : Bounty := (2500, 2.0, 0.002);
Limits : Bounty := ( 0, 25.0, 0.250);
Best : Bounty := ( 0, 0.0, 0.000);
Current : Bounty := ( 0, 0.0, 0.000);
Best_Amounts : array (1 .. 3) of Natural := (0, 0, 0);
Max_Panacea : Natural := Natural (Float'Floor (Min
(Limits.Weight / Panacea.Weight,
Limits.Volume / Panacea.Volume)));
Max_Ichor : Natural := Natural (Float'Floor (Min
(Limits.Weight / Ichor.Weight,
Limits.Volume / Ichor.Volume)));
Max_Gold : Natural := Natural (Float'Floor (Min
(Limits.Weight / Gold.Weight,
Limits.Volume / Gold.Volume)));
begin
for Panacea_Count in 0 .. Max_Panacea loop
for Ichor_Count in 0 .. Max_Ichor loop
for Gold_Count in 0 .. Max_Gold loop
Current.Value := Panacea_Count * Panacea.Value +
Ichor_Count * Ichor.Value +
Gold_Count * Gold.Value;
Current.Weight := Float (Panacea_Count) * Panacea.Weight +
Float (Ichor_Count) * Ichor.Weight +
Float (Gold_Count) * Gold.Weight;
Current.Volume := Float (Panacea_Count) * Panacea.Volume +
Float (Ichor_Count) * Ichor.Volume +
Float (Gold_Count) * Gold.Volume;
if Current.Value > Best.Value and
Current.Weight <= Limits.Weight and
Current.Volume <= Limits.Volume then
Best := Current;
Best_Amounts := (Panacea_Count, Ichor_Count, Gold_Count);
end if;
end loop;
end loop;
end loop;
Ada.Text_IO.Put_Line ("Maximum value:" & Natural'Image (Best.Value));
Ada.Text_IO.Put_Line ("Panacea:" & Natural'Image (Best_Amounts (1)));
Ada.Text_IO.Put_Line ("Ichor: " & Natural'Image (Best_Amounts (2)));
Ada.Text_IO.Put_Line ("Gold: " & Natural'Image (Best_Amounts (3)));
end Knapsack_Unbounded;

View file

@ -0,0 +1,25 @@
Item = Panacea,Ichor,Gold
Value = 3000,1800,2500
Weight= 3,2,20 ; *10
Volume= 25,15,2 ; *1000
StringSplit I, Item, `, ; Put input in arrays
StringSplit W, Weight,`,
StringSplit $, Value, `,
StringSplit V, Volume,`,
SetFormat Float, 0.3
W := 250, V := 250, sW:=.1, sV:=.001 ; limits for the total, scale factors
p := -1, Wp := -W1, Vp := -V1 ; initial values
While (Wp+=W1) <= W && (Vp+=V1) <= V {
p++, Wi := Wp-W2, Vi := Vp-V2, i := -1
While (Wi+=W2) <= W && (Vi+=V2) <= V {
i++, Wg := Wi-W3, Vg := Vi-V3, g := -1
While (Wg+=W3) <= W && (Vg+=V3) <= V
If ($ <= Val := p*$1 + i*$2 + ++g*$3)
t := ($=Val ? t "`n " : " ")
. p "`t " i "`t " g "`t " Wg*sW "`t " Vg*sV
, $ := Val
}
}
MsgBox Value = %$%`n`nPanacea`tIchor`tGold`tWeight`tVolume`n%t%

View file

@ -0,0 +1,70 @@
(knapsack=
( things
= (panacea.3000.3/10.25/1000)
(ichor.1800.2/10.15/1000)
(gold.2500.2.2/1000)
)
& 0:?maxvalue
& :?sack
& ( add
= cumwght
cumvol
cumvalue
cumsack
name
wght
val
vol
tings
n
ncumwght
ncumvalue
ncumvol
. !arg
: ( ?cumwght
. ?cumvol
. ?cumvalue
. ?cumsack
. (?name.?val.?wght.?vol) ?tings
)
& -1:?n
& whl
' ( 1+!n:?n
& !cumwght+!n*!wght:~>25:?ncumwght
& !cumvol+!n*!vol:~>250/1000:?ncumvol
& !cumvalue+!n*!val:?ncumvalue
& ( !tings:
& ( !ncumvalue:>!maxvalue:?maxvalue
& !cumsack
( !n:0&
| ( !cumsack:&Take
| Finally
)
" take "
!n
" items of "
!name
".\n"
)
: ?sack
|
)
| add
$ ( !ncumwght
. !ncumvol
. !ncumvalue
. !cumsack
( !n:0&
| "Take " !n " items of " !name ".\n"
)
. !tings
)
)
)
)
& add$(0.0.0..!things)
& out$(str$(!sack "The value in the knapsack is " !maxvalue "."))
&
);
!knapsack;

View file

@ -0,0 +1,52 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct {
double val, wgt, vol;
const char * name;
} items[] = { // value in hundreds, volume in thousandths
{30, .3, 25, "panacea"},
{18, .2, 15, "ichor"},
{25, 2., 2, "gold"},
{0,0,0,0}
};
/* silly setup for silly task */
int best_cnt[16] = {0}, cnt[16] = {0};
double best_v = 0;
void grab_em(int idx, double cap_v, double cap_w, double v)
{
double val;
int t = cap_w / items[idx].wgt;
cnt[idx] = cap_v / items[idx].vol;
if (cnt[idx] > t) cnt[idx] = t;
while (cnt[idx] >= 0) {
val = v + cnt[idx] * items[idx].val;
if (!items[idx + 1].name) {
if (val > best_v) {
best_v = val;
memcpy(best_cnt, cnt, sizeof(int) * (1 + idx));
}
return;
}
grab_em(idx + 1, cap_v - cnt[idx] * items[idx].vol,
cap_w - cnt[idx] * items[idx].wgt, val);
cnt[idx]--;
}
}
int main(void)
{
int i;
grab_em(0, 250, 25, 0);
printf("value: %g hundreds\n", best_v);
for (i = 0; items[i].name; i++)
printf("%d %s\n", best_cnt[i], items[i].name);
return 0;
}

View file

@ -0,0 +1,9 @@
(defstruct item :value :weight :volume)
(defn total [key items quantities]
(reduce + (map * quantities (map key items))))
(defn max-count [item max-weight max-volume]
(let [mcw (/ max-weight (:weight item))
mcv (/ max-volume (:volume item))]
(min mcw mcv)))

View file

@ -0,0 +1,19 @@
(defn knapsacks []
(let [pan (struct item 3000 0.3 0.025)
ich (struct item 1800 0.2 0.015)
gol (struct item 2500 2.0 0.002)
types [pan ich gol]
max-w 25.0
max-v 0.25
iters #(range (inc (max-count % max-w max-v)))]
(filter (complement nil?)
(pmap
#(let [[p i g] %
w (total :weight types %)
v (total :volume types %)]
(if (and (<= w max-w) (<= v max-v))
(with-meta (struct item (total :value types %) w v) {:p p :i i :g g})))
(for [p (iters pan)
i (iters ich)
g (iters gol)]
[p i g])))))

View file

@ -0,0 +1,10 @@
(defn best-by-value [ks]
(reduce #(if (> (:value %1) (:value %2)) %1 %2) ks))
(defn print-knapsack[k]
(let [ {val :value w :weight v :volume} k
{p :p i :i g :g} ^k]
(println "Maximum value:" (float val))
(println "Total weight: " (float w))
(println "Total volume: " (float v))
(println "Containing: " p "Panacea," i "Ichor," g "Gold")))

View file

@ -0,0 +1,8 @@
(defn all-best-by-value [ks]
(let [b (best-by-value ks)]
(filter #(= (:value b) (:value %)) ks)))
(defn print-knapsacks [ks]
(doseq [k ks]
(print-knapsack k)
(println)))

View file

@ -0,0 +1,44 @@
(defun fill-knapsack (items max-volume max-weight)
"Items is a list of lists of the form (name value weight volume) where weight
and value are integers. max-volume and max-weight, also integers, are the
maximum volume and weight of the knapsack. fill-knapsack returns a list of the
form (total-value inventory total-volume total-weight) where total-value is the
total-value of a knapsack packed with inventory (a list whose elements are
elements of items), and total-weight and total-volume are the total weights and
volumes of the inventory."
;; maxes is a table indexed by volume and weight, where maxes[volume,weight]
;; is a list of the form (value inventory used-volume used-weight) where
;; inventory is a list of items of maximum value fitting within volume and
;; weight, value is the maximum value, and used-volume/used-weight are the
;; actual volume/weight of the inventory.
(let* ((VV (1+ max-volume))
(WW (1+ max-weight))
(maxes (make-array (list VV WW))))
;; fill in the base cases where volume or weight is 0
(dotimes (v VV) (setf (aref maxes v 0) (list 0 '() 0 0)))
(dotimes (w WW) (setf (aref maxes 0 w) (list 0 '() 0 0)))
;; populate the rest of the table. The best value for a volume/weight
;; combination is the best way of adding an item to any of the inventories
;; from [volume-1,weight], [volume,weight-1], or [volume-1,weight-1], or the
;; best of these, if no items can be added.
(do ((v 1 (1+ v))) ((= v VV) (aref maxes max-volume max-weight))
(do ((w 1 (1+ w))) ((= w WW))
(let ((options (sort (list (aref maxes v (1- w))
(aref maxes (1- v) w)
(aref maxes (1- v) (1- w)))
'> :key 'first)))
(destructuring-bind (b-value b-items b-volume b-weight) (first options)
(dolist (option options)
(destructuring-bind (o-value o-items o-volume o-weight) option
(dolist (item items)
(destructuring-bind (_ i-value i-volume i-weight) item
(declare (ignore _))
(when (and (<= (+ o-volume i-volume) v)
(<= (+ o-weight i-weight) w)
(> (+ o-value i-value) b-value))
(setf b-value (+ o-value i-value)
b-volume (+ o-volume i-volume)
b-weight (+ o-weight i-weight)
b-items (list* item o-items)))))))
(setf (aref maxes v w)
(list b-value b-items b-volume b-weight))))))))

View file

@ -0,0 +1,53 @@
import std.stdio, std.algorithm, std.typecons;
struct Bounty {
int value;
double weight, volume;
}
void main() {
immutable Bounty panacea = {3000, 0.3, 0.025};
immutable Bounty ichor = {1800, 0.2, 0.015};
immutable Bounty gold = {2500, 2.0, 0.002};
immutable Bounty sack = { 0, 25.0, 0.25};
Bounty best = {0, 0.0, 0.0};
Bounty current = {0, 0.0, 0.0};
Tuple!(int, int, int) bestAmounts;
immutable maxPanacea = cast(int)(min(sack.weight / panacea.weight,
sack.volume / panacea.volume));
immutable maxIchor = cast(int)(min(sack.weight / ichor.weight,
sack.volume / ichor.volume));
immutable maxGold = cast(int)(min(sack.weight / gold.weight,
sack.volume / gold.volume));
foreach (nPanacea; 0 .. maxPanacea)
foreach (nIchor; 0 .. maxIchor)
foreach (nGold; 0 .. maxGold) {
current.value = nPanacea * panacea.value +
nIchor * ichor.value +
nGold * gold.value;
current.weight = nPanacea * panacea.weight +
nIchor * ichor.weight +
nGold * gold.weight;
current.volume = nPanacea * panacea.volume +
nIchor * ichor.volume +
nGold * gold.volume;
if (current.value > best.value &&
current.weight <= sack.weight &&
current.volume <= sack.volume) {
best = Bounty(current.value,
current.weight,
current.volume);
bestAmounts = tuple(nPanacea, nIchor, nGold);
}
}
writeln("Maximum value achievable is ", best.value);
writefln("This is achieved by carrying (one solution) %d" ~
" panacea, %d ichor and %d gold", bestAmounts.tupleof);
writefln("The weight to carry is %4.1f and the volume used is %5.3f",
best.weight, best.volume);
}

View file

@ -0,0 +1,80 @@
pragma.enable("accumulator")
/** A data type representing a bunch of stuff (or empty space). */
def makeQuantity(value, weight, volume, counts) {
def quantity {
to __printOn(out) {
for name => n in counts { out.print(`$n $name `) }
out.print(`(val=$value wt=$weight vol=$volume)`)
}
to value () { return value }
to weight() { return weight }
to volume() { return volume }
to counts() { return counts }
to subtract(other) { return quantity + other * -1 }
to add(other) {
return makeQuantity(value + other.value (),
weight + other.weight(),
volume + other.volume(),
accum counts for name => n in other.counts() { _.with(name, n+counts.fetch(name, fn {0})) })
}
to multiply(scalar) {
return makeQuantity(value * scalar,
weight * scalar,
volume * scalar,
accum [].asMap() for name => n in counts { _.with(name, n*scalar) })
}
/** a.fit(b) the greatest integer k such that a - b * k does not have negative weight or volume. */
to fit(item) {
return (weight // item.weight()) \
.min(volume // item.volume())
}
}
return quantity
}
/** Fill the space with the treasures, returning candidate results as spaceAvailable - the items. */
def fill(spaceAvailable, treasures) {
if (treasures.size().isZero()) { # nothing to pick
return [spaceAvailable]
}
# Pick one treasure type
def [unit] + otherTreasures := treasures
var results := []
for count in (0..spaceAvailable.fit(unit)).descending() {
results += fill(spaceAvailable - unit * count, otherTreasures)
if (otherTreasures.size().isZero()) {
break # If there are no further kinds, there is no point in taking less than the most
}
}
return results
}
def chooseBest(emptyKnapsack, treasures) {
var maxValue := 0
var best := []
for result in fill(emptyKnapsack, treasures) {
def taken := emptyKnapsack - result # invert the backwards result fill() returns
if (taken.value() > maxValue) {
best := [taken]
maxValue := taken.value()
} else if (taken.value() <=> maxValue) {
best with= taken
}
}
return best
}
def printBest(emptyKnapsack, treasures) {
for taken in chooseBest(emptyKnapsack, treasures) { println(` $taken`) }
}
def panacea := makeQuantity(3000, 0.3, 0.025, ["panacea" => 1])
def ichor := makeQuantity(1800, 0.2, 0.015, ["ichor" => 1])
def gold := makeQuantity(2500, 2.0, 0.002, ["gold" => 1])
def emptyKnapsack \
:= makeQuantity( 0, 25, 0.250, [].asMap())
printBest(emptyKnapsack, [panacea, ichor, gold])

View file

@ -0,0 +1,41 @@
USING: accessors combinators kernel locals math math.order
math.vectors sequences sequences.product combinators.short-circuit ;
IN: knapsack
CONSTANT: values { 3000 1800 2500 }
CONSTANT: weights { 0.3 0.2 2.0 }
CONSTANT: volumes { 0.025 0.015 0.002 }
CONSTANT: max-weight 25.0
CONSTANT: max-volume 0.25
TUPLE: bounty amounts value weight volume ;
: <bounty> ( items -- bounty )
[ bounty new ] dip {
[ >>amounts ]
[ values v. >>value ]
[ weights v. >>weight ]
[ volumes v. >>volume ]
} cleave ;
: valid-bounty? ( bounty -- ? )
{ [ weight>> max-weight <= ]
[ volume>> max-volume <= ] } 1&& ;
M:: bounty <=> ( a b -- <=> )
a valid-bounty? [
b valid-bounty? [
a b [ value>> ] compare
] [ +gt+ ] if
] [ b valid-bounty? +lt+ +eq+ ? ] if ;
: find-max-amounts ( -- amounts )
weights volumes [
[ max-weight swap / ]
[ max-volume swap / ] bi* min >integer
] 2map ;
: best-bounty ( -- bounty )
find-max-amounts [ 1 + iota ] map <product-sequence>
[ <bounty> ] [ max ] map-reduce ;

View file

@ -0,0 +1,60 @@
\ : value ; immediate
: weight cell+ ;
: volume 2 cells + ;
: number 3 cells + ;
\ item value weight volume number
create panacea 30 , 3 , 25 , 0 ,
create ichor 18 , 2 , 15 , 0 ,
create gold 25 , 20 , 2 , 0 ,
create sack 0 , 250 , 250 ,
: fits? ( item -- ? )
dup weight @ sack weight @ > if drop false exit then
volume @ sack volume @ > 0= ;
: add ( item -- )
dup @ sack +!
dup weight @ negate sack weight +!
dup volume @ negate sack volume +!
1 swap number +! ;
: take ( item -- )
dup @ negate sack +!
dup weight @ sack weight +!
dup volume @ sack volume +!
-1 swap number +! ;
variable max-value
variable max-pan
variable max-ich
variable max-au
: .solution
cr
max-pan @ . ." Panaceas, "
max-ich @ . ." Ichors, and "
max-au @ . ." Gold for a total value of "
max-value @ 100 * . ;
: check
sack @ max-value @ <= if exit then
sack @ max-value !
panacea number @ max-pan !
ichor number @ max-ich !
gold number @ max-au !
( .solution ) ; \ and change <= to < to see all solutions
: solve-gold
gold fits? if gold add recurse gold take
else check then ;
: solve-ichor
ichor fits? if ichor add recurse ichor take then
solve-gold ;
: solve-panacea
panacea fits? if panacea add recurse panacea take then
solve-ichor ;
solve-panacea .solution

View file

@ -0,0 +1,34 @@
0 VALUE vials
0 VALUE ampules
0 VALUE bars
0 VALUE bag
#250 3 / #250 #25 / MIN 1+ CONSTANT maxvials
#250 2/ #250 #15 / MIN 1+ CONSTANT maxampules
#250 #20 / #250 2/ MIN 1+ CONSTANT maxbars
: RESULTS ( v a b -- k )
3DUP #20 * SWAP 2* + SWAP 3 * + #250 > IF 3DROP -1 EXIT ENDIF
3DUP 2* SWAP #15 * + SWAP #25 * + #250 > IF 3DROP -1 EXIT ENDIF
#2500 * SWAP #1800 * + SWAP #3000 * + ;
: .SOLUTION ( -- )
CR ." The traveller's knapsack contains "
vials DEC. ." vials of panacea, "
ampules DEC. ." ampules of ichor, "
CR bars DEC. ." bars of gold, a total value of "
vials ampules bars RESULTS 0DEC.R ." ." ;
: KNAPSACK ( -- )
-1 TO bag
maxvials 0 ?DO
maxampules 0 ?DO
maxbars 0 ?DO
K J I RESULTS DUP
bag > IF TO bag K TO vials J TO ampules I TO bars
ELSE DROP
ENDIF
LOOP
LOOP
LOOP
.SOLUTION ;

View file

@ -0,0 +1,48 @@
PROGRAM KNAPSACK
IMPLICIT NONE
REAL :: totalWeight, totalVolume
INTEGER :: maxPanacea, maxIchor, maxGold, maxValue = 0
INTEGER :: i, j, k
INTEGER :: n(3)
TYPE Bounty
INTEGER :: value
REAL :: weight
REAL :: volume
END TYPE Bounty
TYPE(Bounty) :: panacea, ichor, gold, sack, current
panacea = Bounty(3000, 0.3, 0.025)
ichor = Bounty(1800, 0.2, 0.015)
gold = Bounty(2500, 2.0, 0.002)
sack = Bounty(0, 25.0, 0.25)
maxPanacea = MIN(sack%weight / panacea%weight, sack%volume / panacea%volume)
maxIchor = MIN(sack%weight / ichor%weight, sack%volume / ichor%volume)
maxGold = MIN(sack%weight / gold%weight, sack%volume / gold%volume)
DO i = 0, maxPanacea
DO j = 0, maxIchor
Do k = 0, maxGold
current%value = k * gold%value + j * ichor%value + i * panacea%value
current%weight = k * gold%weight + j * ichor%weight + i * panacea%weight
current%volume = k * gold%volume + j * ichor%volume + i * panacea%volume
IF (current%weight > sack%weight .OR. current%volume > sack%volume) CYCLE
IF (current%value > maxValue) THEN
maxValue = current%value
totalWeight = current%weight
totalVolume = current%volume
n(1) = i ; n(2) = j ; n(3) = k
END IF
END DO
END DO
END DO
WRITE(*, "(A,I0)") "Maximum value achievable is ", maxValue
WRITE(*, "(3(A,I0),A)") "This is achieved by carrying ", n(1), " panacea, ", n(2), " ichor and ", n(3), " gold items"
WRITE(*, "(A,F4.1,A,F5.3)") "The weight to carry is ", totalWeight, " and the volume used is ", totalVolume
END PROGRAM KNAPSACK

View file

@ -0,0 +1,70 @@
package main
import "fmt"
type Item struct {
Name string
Value int
Weight, Volume float64
}
type Result struct {
Counts []int
Sum int
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func Knapsack(items []Item, index int, weight, volume float64) (best *Result) {
if index == len(items) {
return &Result{make([]int, len(items)), 0}
}
itemValue := items[index].Value
itemWeight := items[index].Weight
itemVolume := items[index].Volume
maxCount := min(int(weight/itemWeight), int(volume/itemVolume))
for count := 0; count <= maxCount; count++ {
sol := Knapsack(items, index+1,
weight-float64(count)*itemWeight,
volume-float64(count)*itemVolume)
if sol != nil {
sol.Counts[index] = count
sol.Sum += itemValue * count
if best == nil || sol.Sum > best.Sum {
best = sol
}
}
}
return
}
func main() {
items := []Item{
Item{"Panacea", 3000, 0.3, 0.025},
Item{"Ichor", 1800, 0.2, 0.015},
Item{"Gold", 2500, 2.0, 0.002},
}
var sumCount, sumValue int
var sumWeight, sumVolume float64
result := Knapsack(items, 0, 25, 0.25)
for i := range result.Counts {
fmt.Printf("%-8s x%3d -> Weight: %4.1f Volume: %5.3f Value: %6d\n",
items[i].Name, result.Counts[i], items[i].Weight*float64(result.Counts[i]),
items[i].Volume*float64(result.Counts[i]), items[i].Value*result.Counts[i])
sumCount += result.Counts[i]
sumValue += items[i].Value * result.Counts[i]
sumWeight += items[i].Weight * float64(result.Counts[i])
sumVolume += items[i].Volume * float64(result.Counts[i])
}
fmt.Printf("TOTAL (%3d items) Weight: %4.1f Volume: %5.3f Value: %6d\n",
sumCount, sumWeight, sumVolume, sumValue)
}

View file

@ -0,0 +1,24 @@
def totalWeight = { list -> list.collect{ it.item.weight * it.count }.sum() }
def totalVolume = { list -> list.collect{ it.item.volume * it.count }.sum() }
def totalValue = { list -> list.collect{ it.item.value * it.count }.sum() }
def knapsackUnbounded = { possibleItems, BigDecimal weightMax, BigDecimal volumeMax ->
def n = possibleItems.size()
def wm = weightMax.unscaledValue()
def vm = volumeMax.unscaledValue()
def m = (0..n).collect{ i -> (0..wm).collect{ w -> (0..vm).collect{ v -> [] } } }
(1..wm).each { w ->
(1..vm).each { v ->
(1..n).each { i ->
def item = possibleItems[i-1]
def wi = item.weight.unscaledValue()
def vi = item.volume.unscaledValue()
def bi = [w.intdiv(wi),v.intdiv(vi)].min()
m[i][w][v] = (0..bi).collect{ count ->
m[i-1][w - wi * count][v - vi * count] + [[item:item, count:count]]
}.max(totalValue).findAll{ it.count }
}
}
}
m[n][wm][vm]
}

View file

@ -0,0 +1,21 @@
Set solutions = []
items.eachPermutation { itemList ->
def start = System.currentTimeMillis()
def packingList = knapsackUnbounded(itemList, 25.0, 0.250)
def elapsed = System.currentTimeMillis() - start
println "\n Item Order: ${itemList.collect{ it.name.split()[0] }}"
println "Elapsed Time: ${elapsed/1000.0} s"
solutions << (packingList as Set)
}
solutions.each { packingList ->
println "\nTotal Weight: ${totalWeight(packingList)}"
println "Total Volume: ${totalVolume(packingList)}"
println " Total Value: ${totalValue(packingList)}"
packingList.each {
printf (' item: %-22s count:%2d weight:%4.1f Volume:%5.3f\n',
it.item.name, it.count, it.item.weight * it.count, it.item.volume * it.count)
}
}

View file

@ -0,0 +1,38 @@
import Data.List (maximumBy)
import Data.Ord (comparing)
(maxWgt, maxVol) = (25, 0.25)
items =
[Bounty "panacea" 3000 0.3 0.025,
Bounty "ichor" 1800 0.2 0.015,
Bounty "gold" 2500 2.0 0.002]
data Bounty = Bounty
{itemName :: String,
itemVal :: Int,
itemWgt, itemVol :: Double}
names = map itemName items
vals = map itemVal items
wgts = map itemWgt items
vols = map itemVol items
dotProduct :: (Num a, Integral b) => [a] -> [b] -> a
dotProduct factors = sum . zipWith (*) factors . map fromIntegral
options :: [[Int]]
options = filter fits $ mapM f items
where f (Bounty _ _ w v) = [0 .. m]
where m = floor $ min (maxWgt / w) (maxVol / v)
fits opt = dotProduct wgts opt <= maxWgt &&
dotProduct vols opt <= maxVol
showOpt :: [Int] -> String
showOpt opt = concat (zipWith showItem names opt) ++
"total weight: " ++ show (dotProduct wgts opt) ++
"\ntotal volume: " ++ show (dotProduct vols opt) ++
"\ntotal value: " ++ show (dotProduct vals opt) ++ "\n"
where showItem name num = name ++ ": " ++ show num ++ "\n"
main = putStr $ showOpt $ best options
where best = maximumBy $ comparing $ dotProduct vals

View file

@ -0,0 +1,28 @@
CHARACTER list*1000
NN = ALIAS($Panacea, $Ichor, $Gold, wSack, wPanacea, wIchor, wGold, vSack, vPanacea, vIchor, vGold)
NN = (3000, 1800, 2500, 25, 0.3, 0.2, 2.0, 0.25, 0.025, 0.015, 0.002)
maxItems = ALIAS(maxPanacea, maxIchor, maxGold)
maxItems = ( MIN( wSack/wPanacea, vSack/vPanacea), MIN( wSack/wIchor, vSack/vIchor), MIN( wSack/wGold, vSack/vGold) )
maxValue = 0
DO Panaceas = 0, maxPanacea
DO Ichors = 0, maxIchor
DO Golds = 0, maxGold
weight = Panaceas*wPanacea + Ichors*wIchor + Golds*wGold
IF( weight <= wSack ) THEN
volume = Panaceas*vPanacea + Ichors*vIchor + Golds*vGold
IF( volume <= vSack ) THEN
value = Panaceas*$Panacea + Ichors*$Ichor + Golds*$Gold
IF( value > maxValue ) THEN
maxValue = value
! this restarts the list, removing all previous entries:
WRITE(Text=list, Name) value, Panaceas, Ichors, Golds, weight, volume, $CR//$LF
ELSEIF( value == maxValue ) THEN
WRITE(Text=list, Name, APPend) value, Panaceas, Ichors, Golds, weight, volume, $CR//$LF
ENDIF
ENDIF
ENDIF
ENDDO
ENDDO
ENDDO

View file

@ -0,0 +1,4 @@
value=54500; Panaceas=0; Ichors=15; Golds=11; weight=25; volume=0.247;
value=54500; Panaceas=3; Ichors=10; Golds=11; weight=24.9; volume=0.247;
value=54500; Panaceas=6; Ichors=5; Golds=11; weight=24.8; volume=0.247;
value=54500; Panaceas=9; Ichors=0; Golds=11; weight=24.7; volume=0.247;

View file

@ -0,0 +1,18 @@
mwv=: 25 0.25
prods=: <;. _1 ' panacea: ichor: gold:'
hdrs=: <;. _1 ' weight: volume: value:'
vls=: 3000 1800 2500
ws=: 0.3 0.2 2.0
vs=: 0.025 0.015 0.002
ip=: +/ .*
prtscr=: (1!:2)&2
KS=: 3 : 0
os=. (#:i.@(*/)) mwv >:@<.@<./@:% ws,:vs
bo=.os#~(ws,:vs) mwv&(*./@:>)@ip"_ 1 os
mo=.bo{~{.\: vls ip"1 bo
prtscr &.> prods ([,' ',":@])&.>mo
prtscr &.> hdrs ('total '&,@[,' ',":@])&.> mo ip"1 ws,vs,:vls
LF
)

View file

@ -0,0 +1,84 @@
package hu.pj.alg;
import hu.pj.obj.Item;
import java.text.*;
public class UnboundedKnapsack {
protected Item [] items = {
new Item("panacea", 3000, 0.3, 0.025),
new Item("ichor" , 1800, 0.2, 0.015),
new Item("gold" , 2500, 2.0, 0.002)
};
protected final int n = items.length; // the number of items
protected Item sack = new Item("sack" , 0, 25.0, 0.250);
protected Item best = new Item("best" , 0, 0.0, 0.000);
protected int [] maxIt = new int [n]; // maximum number of items
protected int [] iIt = new int [n]; // current indexes of items
protected int [] bestAm = new int [n]; // best amounts
public UnboundedKnapsack() {
// initializing:
for (int i = 0; i < n; i++) {
maxIt [i] = Math.min(
(int)(sack.getWeight() / items[i].getWeight()),
(int)(sack.getVolume() / items[i].getVolume())
);
} // for (i)
// calc the solution:
calcWithRecursion(0);
// Print out the solution:
NumberFormat nf = NumberFormat.getInstance();
System.out.println("Maximum value achievable is: " + best.getValue());
System.out.print("This is achieved by carrying (one solution): ");
for (int i = 0; i < n; i++) {
System.out.print(bestAm[i] + " " + items[i].getName() + ", ");
}
System.out.println();
System.out.println("The weight to carry is: " + nf.format(best.getWeight()) +
" and the volume used is: " + nf.format(best.getVolume())
);
}
// calculation the solution with recursion method
// item : the number of item in the "items" array
public void calcWithRecursion(int item) {
for (int i = 0; i <= maxIt[item]; i++) {
iIt[item] = i;
if (item < n-1) {
calcWithRecursion(item+1);
} else {
int currVal = 0; // current value
double currWei = 0.0; // current weight
double currVol = 0.0; // current Volume
for (int j = 0; j < n; j++) {
currVal += iIt[j] * items[j].getValue();
currWei += iIt[j] * items[j].getWeight();
currVol += iIt[j] * items[j].getVolume();
}
if (currVal > best.getValue()
&&
currWei <= sack.getWeight()
&&
currVol <= sack.getVolume()
)
{
best.setValue (currVal);
best.setWeight(currWei);
best.setVolume(currVol);
for (int j = 0; j < n; j++) bestAm[j] = iIt[j];
} // if (...)
} // else
} // for (i)
} // calcWithRecursion()
// the main() function:
public static void main(String[] args) {
new UnboundedKnapsack();
} // main()
} // class

View file

@ -0,0 +1,51 @@
package hu.pj.obj;
public class Item {
protected String name = "";
protected int value = 0;
protected double weight = 0;
protected double volume = 0;
public Item() {
}
public Item(String name, int value, double weight, double volume) {
setName(name);
setValue(value);
setWeight(weight);
setVolume(volume);
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = Math.max(value, 0);
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = Math.max(weight, 0);
}
public double getVolume() {
return volume;
}
public void setVolume(double volume) {
this.volume = Math.max(volume, 0);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
} // class

View file

@ -0,0 +1,51 @@
var gold = { 'value': 2500, 'weight': 2.0, 'volume': 0.002 },
panacea = { 'value': 3000, 'weight': 0.3, 'volume': 0.025 },
ichor = { 'value': 1800, 'weight': 0.2, 'volume': 0.015 },
items = [gold, panacea, ichor],
knapsack = {'weight': 25, 'volume': 0.25},
max_val = 0,
solutions = [],
g, p, i, item, val;
for (i = 0; i < items.length; i += 1) {
item = items[i];
item.max = Math.min(
Math.floor(knapsack.weight / item.weight),
Math.floor(knapsack.volume / item.volume)
);
}
for (g = 0; g <= gold.max; g += 1) {
for (p = 0; p <= panacea.max; p += 1) {
for (i = 0; i <= ichor.max; i += 1) {
if (i * ichor.weight + g * gold.weight + p * panacea.weight > knapsack.weight) {
continue;
}
if (i * ichor.volume + g * gold.volume + p * panacea.volume > knapsack.volume) {
continue;
}
val = i * ichor.value + g * gold.value + p * panacea.value;
if (val > max_val) {
solutions = [];
max_val = val;
}
if (val === max_val) {
solutions.push([g, p, i]);
}
}
}
}
document.write("maximum value: " + max_val + '<br>');
for (i = 0; i < solutions.length; i += 1) {
item = solutions[i];
document.write("(gold: " + item[0] + ", panacea: " + item[1] + ", ichor: " + item[2] + ")<br>");
}
output:
<pre>maximum value: 54500
(gold: 11, panacea: 0, ichor: 15)
(gold: 11, panacea: 3, ichor: 10)
(gold: 11, panacea: 6, ichor: 5)
(gold: 11, panacea: 9, ichor: 0)</pre>

View file

@ -0,0 +1,36 @@
items = { ["panaea"] = { ["value"] = 3000, ["weight"] = 0.3, ["volume"] = 0.025 },
["ichor"] = { ["value"] = 1800, ["weight"] = 0.2, ["volume"] = 0.015 },
["gold"] = { ["value"] = 2500, ["weight"] = 2.0, ["volume"] = 0.002 }
}
max_weight = 25
max_volume = 0.25
max_num_items = {}
for i in pairs( items ) do
max_num_items[i] = math.floor( math.min( max_weight / items[i].weight, max_volume / items[i].volume ) )
end
best = { ["value"] = 0.0, ["weight"] = 0.0, ["volume"] = 0.0 }
best_amounts = {}
for i = 1, max_num_items["panaea"] do
for j = 1, max_num_items["ichor"] do
for k = 1, max_num_items["gold"] do
current = { ["value"] = i*items["panaea"]["value"] + j*items["ichor"]["value"] + k*items["gold"]["value"],
["weight"] = i*items["panaea"]["weight"] + j*items["ichor"]["weight"] + k*items["gold"]["weight"],
["volume"] = i*items["panaea"]["volume"] + j*items["ichor"]["volume"] + k*items["gold"]["volume"]
}
if current.value > best.value and current.weight <= max_weight and current.volume <= max_volume then
best = { ["value"] = current.value, ["weight"] = current.weight, ["volume"] = current.volume }
best_amounts = { ["panaea"] = i, ["ichor"] = j, ["gold"] = k }
end
end
end
end
print( "Maximum value:", best.value )
for k, v in pairs( best_amounts ) do
print( k, v )
end

View file

@ -0,0 +1,34 @@
divert(-1)
define(`set2d',`define(`$1[$2][$3]',`$4')')
define(`get2d',`defn(`$1[$2][$3]')')
define(`for',
`ifelse($#,0,``$0'',
`ifelse(eval($2<=$3),1,
`pushdef(`$1',$2)$4`'popdef(`$1')$0(`$1',incr($2),$3,`$4')')')')
define(`min',
`define(`ma',eval($1))`'define(`mb',eval($2))`'ifelse(eval(ma<mb),1,ma,mb)')
define(`setv',
`set2d($1,$2,1,$3)`'set2d($1,$2,2,$4)`'set2d($1,$2,3,$5)`'set2d($1,$2,4,$6)')
dnl name,value (each),weight,volume
setv(a,0,`knapsack',0,250,250)
setv(a,1,`panacea',3000,3,25)
setv(a,2,`ichor',1800,2,15)
setv(a,3,`gold',2500,20,2)
define(`mv',0)
for(`x',0,min(get2d(a,0,3)/get2d(a,1,3),get2d(a,0,4)/get2d(a,1,4)),
`for(`y',0,min((get2d(a,0,3)-x*get2d(a,1,3))/get2d(a,2,3),
(get2d(a,0,4)-x*get2d(a,1,4))/get2d(a,2,4)),
`
define(`z',min((get2d(a,0,3)-x*get2d(a,1,3)-y*get2d(a,2,3))/get2d(a,3,3),
(get2d(a,0,4)-x*get2d(a,1,4)-y*get2d(a,2,4))/get2d(a,3,4)))
define(`cv',eval(x*get2d(a,1,2)+y*get2d(a,2,2)+z*get2d(a,3,2)))
ifelse(eval(cv>mv),1,
`define(`mv',cv)`'define(`best',(x,y,z))',
`ifelse(cv,mv,`define(`best',best (x,y,z))')')
')')
divert
mv best

View file

@ -0,0 +1,10 @@
{pva,pwe,pvo}={3000,3/10,1/40};
{iva,iwe,ivo}={1800,2/10,3/200};
{gva,gwe,gvo}={2500,2,2/1000};
wemax=25;
vomax=1/4;
{pmax,imax,gmax}=Floor/@{Min[vomax/pvo,wemax/pwe],Min[vomax/ivo,wemax/iwe],Min[vomax/gvo,wemax/gwe]};
data=Flatten[Table[{{p,i,g}.{pva,iva,gva},{p,i,g}.{pwe,iwe,gwe},{p,i,g}.{pvo,ivo,gvo},{p,i,g}},{p,0,pmax},{i,0,imax},{g,0,gmax}],2];
data=Select[data,#[[2]]<=25&&#[[3]]<=1/4&];
First[SplitBy[Sort[data,First[#1]>First[#2]&],First]]

View file

@ -0,0 +1 @@
{{54500,247/10,247/1000,{9,0,11}},{54500,124/5,247/1000,{6,5,11}},{54500,249/10,247/1000,{3,10,11}},{54500,25,247/1000,{0,15,11}}}

View file

@ -0,0 +1,4 @@
p:9 i:0 v:11
p:6 i:5 v:11
p:3 i:10 v:11
p:0 i:15 v:11

View file

@ -0,0 +1,29 @@
/*Knapsack
This model finds the integer optimal packing of a knapsack
Nigel_Galloway
January 9th., 2012
*/
set Items;
param weight{t in Items};
param value{t in Items};
param volume{t in Items};
var take{t in Items}, integer, >=0;
knap_weight : sum{t in Items} take[t] * weight[t] <= 25;
knap_vol : sum{t in Items} take[t] * volume[t] <= 0.25;
maximize knap_value: sum{t in Items} take[t] * value[t];
data;
param : Items : weight value volume :=
panacea 0.3 3000 0.025
ichor 0.2 1800 0.015
gold 2.0 2500 0.002
;
end;

View file

@ -0,0 +1,47 @@
MODULE Knapsack EXPORTS Main;
FROM IO IMPORT Put;
FROM Fmt IMPORT Int, Real;
TYPE Bounty = RECORD
value: INTEGER;
weight, volume: REAL;
END;
VAR totalWeight, totalVolume: REAL;
maxPanacea, maxIchor, maxGold, maxValue: INTEGER := 0;
n: ARRAY [1..3] OF INTEGER;
panacea, ichor, gold, sack, current: Bounty;
BEGIN
panacea := Bounty{3000, 0.3, 0.025};
ichor := Bounty{1800, 0.2, 0.015};
gold := Bounty{2500, 2.0, 0.002};
sack := Bounty{0, 25.0, 0.25};
maxPanacea := FLOOR(MIN(sack.weight / panacea.weight, sack.volume / panacea.volume));
maxIchor := FLOOR(MIN(sack.weight / ichor.weight, sack.volume / ichor.volume));
maxGold := FLOOR(MIN(sack.weight / gold.weight, sack.volume / gold.volume));
FOR i := 0 TO maxPanacea DO
FOR j := 0 TO maxIchor DO
FOR k := 0 TO maxGold DO
current.value := k * gold.value + j * ichor.value + i * panacea.value;
current.weight := FLOAT(k) * gold.weight + FLOAT(j) * ichor.weight + FLOAT(i) * panacea.weight;
current.volume := FLOAT(k) * gold.volume + FLOAT(j) * ichor.volume + FLOAT(i) * panacea.volume;
IF current.weight > sack.weight OR current.volume > sack.volume THEN
EXIT;
END;
IF current.value > maxValue THEN
maxValue := current.value;
totalWeight := current.weight;
totalVolume := current.volume;
n[1] := i; n[2] := j; n[3] := k;
END;
END;
END;
END;
Put("Maximum value achievable is " & Int(maxValue) & "\n");
Put("This is achieved by carrying " & Int(n[1]) & " panacea, " & Int(n[2]) & " ichor and " & Int(n[3]) & " gold items\n");
Put("The weight of this carry is " & Real(totalWeight) & " and the volume used is " & Real(totalVolume) & "\n");
END Knapsack.

View file

@ -0,0 +1,71 @@
my (@names, @val, @weight, @vol, $max_vol, $max_weight, $vsc, $wsc);
if (1) { # change 1 to 0 for different data set
@names = qw(panacea icor gold);
@val = qw(3000 1800 2500);
@weight = qw(3 2 20 );
@vol = qw(25 15 2 );
$max_weight = 250;
$max_vol = 250;
$vsc = 1000;
$wsc = 10;
} else { # with these numbers cache would have been useful
@names = qw(panacea icor gold banana monkey );
@val = qw(17 11 5 3 34 );
@weight = qw(14 3 2 2 10 );
@vol = qw(3 4 2 1 12 );
$max_weight = 150;
$max_vol = 100;
$vsc = $wsc = 1;
}
my @cache;
my ($hits, $misses) = (0, 0);
sub solu {
my ($i, $w, $v) = @_;
return [0, []] if $i < 0;
if ($cache[$i][$w][$v]) {
$hits ++;
return $cache[$i][$w][$v]
}
$misses ++;
my $x = solu($i - 1, $w, $v);
my ($w1, $v1);
for (my $t = 1; ; $t++) {
last if ($w1 = $w - $t * $weight[$i]) < 0;
last if ($v1 = $v - $t * $vol[$i]) < 0;
my $y = solu($i - 1, $w1, $v1);
if ( (my $tmp = $y->[0] + $val[$i] * $t) > $x->[0] ) {
$x = [ $tmp, [ @{$y->[1]}, [$i, $t] ] ];
}
}
$cache[$i][$w][$v] = $x
}
my $x = solu($#names, $max_weight, $max_vol);
print "Max value $x->[0], with:\n",
" Item\tQty\tWeight Vol Value\n", '-'x 50, "\n";
my ($wtot, $vtot) = (0, 0);
for (@{$x->[1]}) {
my $i = $_->[0];
printf " $names[$i]:\t% 3d % 8d% 8g% 8d\n",
$_->[1],
$weight[$i] * $_->[1] / $wsc,
$vol[$i] * $_->[1] / $vsc,
$val[$i] * $_->[1];
$wtot += $weight[$i] * $_->[1];
$vtot += $vol[$i] * $_->[1];
}
print "-" x 50, "\n";
printf " Total:\t % 8d% 8g% 8d\n",
$wtot/$wsc, $vtot/$vsc, $x->[0];
print "\nCache hit: $hits\tmiss: $misses\n";

View file

@ -0,0 +1,24 @@
(de *Items
("panacea" 3 25 3000)
("ichor" 2 15 1800)
("gold" 20 2 2500) )
(de knapsack (Lst W V)
(when Lst
(let X (knapsack (cdr Lst) W V)
(if (and (ge0 (dec 'W (cadar Lst))) (ge0 (dec 'V (caddar Lst))))
(maxi
'((L) (sum cadddr L))
(list
X
(cons (car Lst) (knapsack (cdr Lst) W V))
(cons (car Lst) (knapsack Lst W V)) ) )
X ) ) ) )
(let K (knapsack *Items 250 250)
(for (L K L)
(let (N 1 X)
(while (= (setq X (pop 'L)) (car L))
(inc 'N) )
(apply tab X (4 2 8 5 5 7) N "x") ) )
(tab (14 5 5 7) NIL (sum cadr K) (sum caddr K) (sum cadddr K)) )

View file

@ -0,0 +1,86 @@
:- use_module(library(simplex)).
% tuples (name, Explantion, Value, weights, volume).
knapsack :-
L =[( panacea, 'Incredible healing properties', 3000, 0.3, 0.025),
( ichor, 'Vampires blood', 1800, 0.2, 0.015),
( gold , 'Shiney shiney', 2500, 2.0, 0.002)],
gen_state(S0),
length(L, N),
numlist(1, N, LN),
% to get statistics
time((create_constraint_N(LN, L, S0, S1, [], LVa, [], LW, [], LVo),
constraint(LW =< 25.0, S1, S2),
constraint(LVo =< 0.25, S2, S3),
maximize(LVa, S3, S4)
)),
% we display the results
compute_lenword(L, 0, Len),
sformat(A0, '~~w~~t~~~w|', [3]),
sformat(A1, '~~w~~t~~~w|', [Len]),
sformat(A2, '~~t~~w~~~w|', [10]),
sformat(A3, '~~t~~2f~~~w|', [10]),
sformat(A4, '~~t~~3f~~~w|', [10]),
sformat(A33, '~~t~~w~~~w|', [10]),
sformat(A44, '~~t~~w~~~w|', [10]),
sformat(W0, A0, ['Nb']),
sformat(W1, A1, ['Items']),
sformat(W2, A2, ['Value']),
sformat(W3, A33, ['Weigth']),
sformat(W4, A44, ['Volume']),
format('~w~w~w~w~w~n', [W0, W1,W2,W3,W4]),
print_results(S4, A0, A1, A2, A3, A4, L, LN, 0, 0, 0).
create_constraint_N([], [], S, S, LVa, LVa, LW, LW, LVo, LVo).
create_constraint_N([HN|TN], [(_, _,Va, W, Vo) | TL], S1, SF, LVa, LVaF, LW, LWF, LVo, LVoF) :-
constraint(integral(x(HN)), S1, S2),
constraint([x(HN)] >= 0, S2, S3),
create_constraint_N(TN, TL, S3, SF,
[Va * x(HN) | LVa], LVaF,
[W * x(HN) | LW], LWF,
[Vo * x(HN) | LVo], LVoF).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
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).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
print_results(_S, A0, A1, A2, A3, A4, [], [], VaM, WM, VoM) :-
sformat(W0, A0, [' ']),
sformat(W1, A1, [' ']),
sformat(W2, A2, [VaM]),
sformat(W3, A3, [WM]),
sformat(W4, A4, [VoM]),
format('~w~w~w~w~w~n', [W0, W1,W2,W3,W4]).
print_results(S, A0, A1, A2, A3, A4, [(Name, _, Va, W, Vo)|T], [N|TN], Va1, W1, Vo1) :-
variable_value(S, x(N), X),
( X = 0 -> Va1 = Va2, W1 = W2, Vo1 = Vo2
;
sformat(S0, A0, [X]),
sformat(S1, A1, [Name]),
Vatemp is X * Va,
Wtemp is X * W,
Votemp is X * Vo,
sformat(S2, A2, [Vatemp]),
sformat(S3, A3, [Wtemp]),
sformat(S4, A4, [Votemp]),
format('~w~w~w~w~w~n', [S0,S1,S2,S3,S4]),
Va2 is Va1 + Vatemp,
W2 is W1 + Wtemp,
Vo2 is Vo1 + Votemp ),
print_results(S, A0, A1, A2, A3, A4, T, TN, Va2, W2, Vo2).

View file

@ -0,0 +1,22 @@
# Define consts
weights <- c(panacea=0.3, ichor=0.2, gold=2.0)
volumes <- c(panacea=0.025, ichor=0.015, gold=0.002)
values <- c(panacea=3000, ichor=1800, gold=2500)
sack.weight <- 25
sack.volume <- 0.25
max.items <- floor(pmin(sack.weight/weights, sack.volume/volumes))
# Some utility functions
getTotalValue <- function(n) sum(n*values)
getTotalWeight <- function(n) sum(n*weights)
getTotalVolume <- function(n) sum(n*volumes)
willFitInSack <- function(n) getTotalWeight(n) <= sack.weight && getTotalVolume(n) <= sack.volume
# Find all possible combination, then eliminate those that won't fit in the sack
knapsack <- expand.grid(lapply(max.items, function(n) seq.int(0, n)))
ok <- apply(knapsack, 1, willFitInSack)
knapok <- knapsack[ok,]
# Find the solutions with the highest value
vals <- apply(knapok, 1, getTotalValue)
knapok[vals == max(vals),]

View file

@ -0,0 +1,46 @@
/*REXX program solves a knapsack/unbounded problem. */
maxPanacea=0
maxIchor =0
maxGold =0
max$ =0
current. =0
/* value weight volume */
/* ═══════ ═══════ ══════ */
panacea.$= 3000 ; panacea.w= 0.3 ; panacea.v= 0.025
ichor.$= 1800 ; ichor.w= 0.2 ; ichor.v= 0.015
gold.$= 2500 ; gold.w= 2 ; gold.v= 0.002
sack.$= 0 ; sack.w= 25 ; sack.v= 0.25
maxPanacea = min(sack.w/panacea.w, sack.v/panacea.v)
maxIchor = min(sack.w/ ichor.w, sack.v/ ichor.v)
maxGold = min(sack.w/ gold.w, sack.v/ gold.v)
do p=0 to maxpanacea
do i=0 to maxichor
do g=0 to maxgold
current.$=g*gold.$ + i*ichor.$ + p*panacea.$
current.w=g*gold.w + i*ichor.w + p*panacea.w
current.v=g*gold.v + i*ichor.v + p*panacea.v
if current.w>sack.w | current.v>sack.v then iterate
if current.$>max$ then do
max$ = current.$
totalW = current.w
totalV = current.v
maxP=p; maxI=i; maxG=g
end
end /*g (gold) */
end /*i (ichor) */
end /*p (panacea)*/
cTot=maxP+maxI+maxG
L=length(cTot)+1
say ' panacea in sack:' right(maxP,L)
say ' ichors in sack:' right(maxI,L)
say ' gold items in sack:' right(maxG,L)
say '' copies('',L)
say 'carrying a total of:' right(cTot,L)
say left('',40) 'total value: ' max$/1
say left('',40) 'total weight: ' totalW/1
say left('',40) 'total volume: ' totalV/1
/*stick a fork in it, we're done.*/

View file

@ -0,0 +1,37 @@
KnapsackItem = Struct.new(:volume, :weight, :value)
panacea = KnapsackItem.new(0.025, 0.3, 3000)
ichor = KnapsackItem.new(0.015, 0.2, 1800)
gold = KnapsackItem.new(0.002, 2.0, 2500)
maximum = KnapsackItem.new(0.25, 25, 0)
max_items = {}
for item in [panacea, ichor, gold]
max_items[item] = [(maximum.volume/item.volume).to_i, (maximum.weight/item.weight).to_i].min
end
maxval = 0
solutions = []
0.upto(max_items[ichor]) do |i|
0.upto(max_items[panacea]) do |p|
0.upto(max_items[gold]) do |g|
next if i*ichor.weight + p*panacea.weight + g*gold.weight > maximum.weight
next if i*ichor.volume + p*panacea.volume + g*gold.volume > maximum.volume
val = i*ichor.value + p*panacea.value + g*gold.value
if val > maxval
maxval = val
solutions = [[i, p, g]]
elsif val == maxval
solutions << [i, p, g]
end
end
end
end
puts "The maximal solution has value #{maxval}"
solutions.each do |i, p, g|
printf " ichor=%2d, panacea=%2d, gold=%2d -- weight:%.1f, volume=%.3f\n",
i, p, g,
i*ichor.weight + p*panacea.weight + g*gold.weight,
i*ichor.volume + p*panacea.volume + g*gold.volume
end

View file

@ -0,0 +1,31 @@
#!/usr/bin/env tclsh
proc main argv {
array set value {panacea 3000 ichor 1800 gold 2500}
array set weight {panacea 0.3 ichor 0.2 gold 2.0 max 25}
array set volume {panacea 0.025 ichor 0.015 gold 0.002 max 0.25}
foreach i {panacea ichor gold} {
set max($i) [expr {min(int($volume(max)/$volume($i)),
int($weight(max)/$weight($i)))}]
}
set maxval 0
for {set i 0} {$i < $max(ichor)} {incr i} {
for {set p 0} {$p < $max(panacea)} {incr p} {
for {set g 0} {$g < $max(gold)} {incr g} {
if {$i*$weight(ichor) + $p*$weight(panacea) + $g*$weight(gold)
> $weight(max)} continue
if {$i*$volume(ichor) + $p*$volume(panacea) + $g*$volume(gold)
> $volume(max)} continue
set val [expr {$i*$value(ichor)+$p*$value(panacea)+$g*$value(gold)}]
if {$val == $maxval} {
lappend best [list i $i p $p g $g]
} elseif {$val > $maxval} {
set maxval $val
set best [list [list i $i p $p g $g]]
}
}
}
}
puts "maxval: $maxval, best: $best"
}
main $argv