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.

Item

Explanation

Value (each)

weight

Volume (each)

panacea
(vials of)

Incredible healing properties

3000

0.3

0.025

ichor
(ampules of)

Vampires blood

1800

0.2

0.015

gold
(bars)

Shiney shiney

2500

2.0

0.002

Knapsack

For the carrying of

-

<=25

<=0.25

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.

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);

# (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 DOFOR 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 TOUPB 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]:= candidateFIFIODODOD;

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))

Output:

The maximum value achievable (by dynamic programming) is +54500
The number of (panacea, ichor, gold) items to achieve this is: ( 9, 0, 11) respectively
The weight to carry is 247, and the volume used is 247

We have an item struct to contain the data for both contents and the knapsack. The total function returns the sum of a particular attribute across all items times their quantities. Finally, the max-count function returns the most of that item that could fit given the constraints (used as the upper bound on the combination). Now the real work:

The knapsacks function returns a lazy sequence of all valid knapsacks, with the particular content quantities as metadata. The work of realizing each knapsack is done in parallel via the pmap function. The following then finds the best by value, and prints the result.

This is a mostly brute-force general solution (the first author of this example does not know dynamic programming); the only optimization is that when considering the last (third) treasure type, it does not bother filling with anything but the maximum amount.

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}

While this solver can only be used to detect two of the four possible solutions, the other two may be discovered by noting that 5 ampules of ichor and 3 vials of panacea have the same value and the same volume and only differ by 0.1 in weight. Thus the other two solutions can be derived by substitution as follows:

If you study the output, you see how the weight and volume equations automagically constrain the domain of the three variables.
Afterwards SearchBest only has to evaluate 38 different combinations to find an optimal solution:

Dynamic programming solution. Before you ask, no, it's actually slower for the given data set. See the alternate data set.

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(300018002500);@weight=qw(3220);@vol=qw(25152);$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(17115334);@weight=qw(1432210);@vol=qw(342112);$max_weight=150;$max_vol=100;$vsc=$wsc=1;}

The algorithm is to enumerate all packings with up to the maximum of each item,
filter them by the volume and weight restrictions, partition the remaining packings
by value, and search for the maximum value class.