Another update from ingydotnet^djgoku

This commit is contained in:
Ingy döt Net 2015-11-18 06:14:39 +00:00
parent 91df62d461
commit 948b86eafa
7604 changed files with 108452 additions and 22726 deletions

View file

@ -42,24 +42,36 @@ typedef struct {
void optimal(int weight, int idx, solution *s)
{
solution v1, v2;
if (idx < 0) {
s->bits = s->value = 0;
return;
}
function solve(itemArray, capacity){
matrix = create2DMatrix(itemArray.length, capacity);
keep_matrix = create2DMatrix(itemArray.length, capacity);
for(var c=0; c <= capacity; c++){
matrix[0][c] = 0;
keep_matrix[0][c] = 0;
}
for(var r=1; r<itemArray.length+1; ++r){//rows
for(var c=0; c<=capacity; ++c){
var toMatrix = 0;
//fit in itself?
var fit = items[r-1].weight<= c;
if(fit){//add remaining mini-knapsack if any, and compare to not putting it
var restCap = c-items[r-1].weight;
toMatrix = items[r-1].value+ matrix[r-1][restCap];
if( toMatrix > matrix[r-1][c])
keep_matrix[r][c] = 1;
else
keep_matrix[r][c] = 0;
toMatrix = Math.max(toMatrix, matrix[r-1][c]);
}else{//copy the knapsack from row above
toMatrix = matrix[r-1][c];
keep_matrix[r][c] = 0;
}
matrix[r][c] = toMatrix;
}
}
return matrix;
}
if (weight < item[idx].weight) {
optimal(weight, idx - 1, s);
return;
}
optimal(weight, idx - 1, &v1);
optimal(weight - item[idx].weight, idx - 1, &v2);
v2.value += item[idx].value;
v2.bits |= (1 << idx);
*s = (v1.value >= v2.value) ? v1 : v2;
}
int main(void)

View file

@ -0,0 +1,40 @@
class
APPLICATION
create
make
feature {NONE} -- Initialization
make
local
knapsack: KNAPSACKZEROONE
do
create knapsack.make (400)
knapsack.add_item (create {ITEM}.make ("", 0, 0))
knapsack.add_item (create {ITEM}.make ("map", 9, 150))
knapsack.add_item (create {ITEM}.make ("compass", 13, 35))
knapsack.add_item (create {ITEM}.make ("water", 153, 200))
knapsack.add_item (create {ITEM}.make ("sandwich", 50, 160))
knapsack.add_item (create {ITEM}.make ("glucose", 15, 60))
knapsack.add_item (create {ITEM}.make ("tin", 68, 45))
knapsack.add_item (create {ITEM}.make ("banana", 27, 60))
knapsack.add_item (create {ITEM}.make ("apple", 39, 40))
knapsack.add_item (create {ITEM}.make ("cheese", 23, 30))
knapsack.add_item (create {ITEM}.make ("beer", 52, 10))
knapsack.add_item (create {ITEM}.make ("suntan cream", 11, 70))
knapsack.add_item (create {ITEM}.make ("camera", 32, 30))
knapsack.add_item (create {ITEM}.make ("T-shirt", 24, 15))
knapsack.add_item (create {ITEM}.make ("trousers", 48, 10))
knapsack.add_item (create {ITEM}.make ("umbrella, ella ella", 73, 40))
knapsack.add_item (create {ITEM}.make ("waterproof trousers", 42, 70))
knapsack.add_item (create {ITEM}.make ("waterproof overclothes", 43, 75))
knapsack.add_item (create {ITEM}.make ("note-case", 22, 80))
knapsack.add_item (create {ITEM}.make ("sunglasses", 7, 20))
knapsack.add_item (create {ITEM}.make ("towel", 18, 12))
knapsack.add_item (create {ITEM}.make ("socks", 4, 50))
knapsack.add_item (create {ITEM}.make ("book", 30, 10))
knapsack.compute_solution
end
end

View file

@ -0,0 +1,35 @@
class
ITEM
create
make, make_from_other
feature
name: STRING
weight: INTEGER
value: INTEGER
make_from_other (other: ITEM)
-- Item with name, weight and value set to 'other's name, weight and value.
do
name := other.name
weight := other.weight
value := other.value
end
make (a_name: String; a_weight, a_value: INTEGER)
-- Item with name, weight and value set to 'a_name', 'a_weight' and 'a_value'.
require
a_name /= Void
a_weight >= 0
a_value >= 0
do
name := a_name
weight := a_weight
value := a_value
end
end

View file

@ -0,0 +1,106 @@
class
KNAPSACKZEROONE
create
make
feature
items: ARRAY [ITEM]
max_weight: INTEGER
feature
make (a_max_weight: INTEGER)
-- Make an empty knapsack.
require
a_max_weight >= 0
do
create items.make_empty
max_weight := a_max_weight
end
add_item (item: ITEM)
-- Add 'item' to knapsack.
local
temp: ITEM
do
create temp.make_from_other (item)
items.force (item, items.count + 1)
end
compute_solution
local
M: ARRAY [INTEGER]
n: INTEGER
i, j: INTEGER
w_i, v_i: INTEGER
item_i: ITEM
final_items: LINKED_LIST [ITEM]
do
n := items.count
create M.make_filled (0, 1, n * max_weight)
from
i := 2
until
(i > n)
loop
from
j := 1
until
j > max_weight
loop
item_i := items [i]
w_i := item_i.weight
if w_i <= j then
v_i := item_i.value
M [(i - 1) * max_weight + j] := max (M [(i - 2) * max_weight + j], M [(i - 2) * max_weight + j - w_i + 1] + v_i)
else
M [(i - 1) * max_weight + j] := M [(i - 2) * max_weight + j]
end
j := j + 1
end
i := i + 1
end
io.put_string ("The final value of the knapsack will be: ")
io.put_integer (M [(n - 1) * max_weight + max_weight]);
io.new_line
--compute the items that fit into the knapsack
create final_items.make
io.put_string ("We'll take the following items: %N");
from
i := n
j := max_weight
until
i <= 1 or j <= 1
loop
item_i := items [i]
w_i := item_i.weight
if w_i <= j then
v_i := item_i.value
if M [(i - 1) * max_weight + j] = M [(i - 2) * max_weight + j] then
else
final_items.extend (item_i)
io.put_string (item_i.name)
io.new_line
j := j - w_i
end
else
end
i := i - 1
end
end
feature {NONE}
max (a, b: INTEGER): INTEGER
-- Max of 'a' and 'b'.
do
Result := a
if a < b then
Result := b
end
end
end

View file

@ -0,0 +1,70 @@
\ Rosetta Code Knapp-sack 0-1 problem. Tested under GForth 0.7.3.
\ 22 items. On current processors a set fits nicely in one CELL (32 or 64 bits).
\ Brute force approach: for every possible set of 22 items,
\ check for admissible solution then for optimal set.
: offs HERE over - ;
400 VALUE WLIMIT
0 VALUE ITEM
0 VALUE VAL
0 VALUE /ITEM
0 VALUE ITEMS#
Create Sack
HERE
9 , offs TO VAL
150 , offs TO ITEM
s" map " s, offs TO /ITEM
DROP
13 , 35 , s" compass " s,
153 , 200 , s" water " s,
50 , 160 , s" sandwich " s,
15 , 60 , s" glucose " s,
68 , 45 , s" tin " s,
27 , 60 , s" banana " s,
39 , 40 , s" apple " s,
23 , 30 , s" cheese " s,
52 , 10 , s" beer " s,
11 , 70 , s" suntan cream " s,
32 , 30 , s" camera " s,
24 , 15 , s" T-shirt " s,
48 , 10 , s" trousers " s,
73 , 40 , s" umbrella " s,
42 , 70 , s" wp trousers " s,
43 , 75 , s" wp overclothes " s,
22 , 80 , s" note-case " s,
7 , 20 , s" sunglasses " s,
18 , 12 , s" towel " s,
4 , 50 , s" socks " s,
30 , 10 , s" book " s,
HERE VALUE END-SACK
VARIABLE Sol \ Solution Set
VARIABLE Vmax \ Temporary Maximum Value
VARIABLE Sum \ Temporary Sum (for speed-up)
: ]sum ( Rtime: set -- sum ;Ctime: hilimit.a start.a -- )
\ Loop unwinding & precomputing addresses
]
]] Sum OFF [[
DO ]] dup [[ 1 ]] LITERAL AND IF [[ I ]] LITERAL @ Sum +! THEN 2/ [[
/ITEM +LOOP ]] drop Sum @ [[
; IMMEDIATE
: solve ( -- )
Vmax OFF
[ 1 END-SACK Sack - /ITEM / lshift 1- ]L 0
DO
I [ END-SACK Sack ]sum ( by weight ) WLIMIT <
IF
I [ END-SACK VAL + Sack VAL + ]sum ( by value )
dup Vmax @ >
IF Vmax ! I Sol ! ELSE drop THEN
THEN
LOOP
;
: .solution ( -- )
Sol @ END-SACK ITEM + Sack ITEM +
DO
dup 1 AND IF I count type cr THEN
2/
/ITEM +LOOP
drop
." Weight: " Sol @ [ END-SACK Sack ]sum . ." Value: " Sol @ [ END-SACK VAL + Sack VAL + ]sum .
;

View file

@ -0,0 +1,20 @@
using MathProgBase
immutable KPDSupply{S<:String, T<:Integer}
item::S
weight::T
value::T
quant::T
end
function KPDSupply{S<:String, T<:Integer}(item::S, weight::T, value::T)
KPDSupply(item, weight, value, one(T))
end
function solve{S<:String, T<:Integer}(gear::Array{KPDSupply{S,T},1},
capacity::T)
w = map(x->x.weight, gear)
v = map(x->x.value, gear)
sol = mixintprog(-v, w', '<', capacity, :Bin, 0, 1)
sol.status == :Optimal || error("This Problem could not be solved")
gear[sol.sol .== 1.0]
end

View file

@ -0,0 +1,32 @@
gear = [KPDSupply("map", 9, 150),
KPDSupply("compass", 13, 35),
KPDSupply("water", 153, 200),
KPDSupply("sandwich", 50, 160),
KPDSupply("glucose", 15, 60),
KPDSupply("tin", 68, 45),
KPDSupply("banana", 27, 60),
KPDSupply("apple", 39, 40),
KPDSupply("cheese", 23, 30),
KPDSupply("beer", 52, 10),
KPDSupply("suntan cream", 11, 70),
KPDSupply("camera", 32, 30),
KPDSupply("T-shirt", 24, 15),
KPDSupply("trousers", 48, 10),
KPDSupply("umbrella", 73, 40),
KPDSupply("waterproof trousers", 42, 70),
KPDSupply("waterproof overclothes", 43, 75),
KPDSupply("note-case", 22, 80),
KPDSupply("sunglasses", 7, 20),
KPDSupply("towel", 18, 12),
KPDSupply("socks", 4, 50),
KPDSupply("book", 30, 10)]
pack = solve(gear, 400)
println("The hiker should pack:")
for s in pack
println(" ", s.item)
end
println()
println("Packed Weight: ", mapreduce(x->x.weight, +, pack))
println("Packed Value: ", mapreduce(x->x.value, +, pack))

View file

@ -12,7 +12,7 @@
#
#########################################################
function knapSolveFast2($w,$v,$i,$aW,&$m) {
function knapSolveFast2($w, $v, $i, $aW, &$m, &$pickedItems) {
global $numcalls;
$numcalls ++;
@ -92,6 +92,7 @@ echo "<b>Array Indices:</b><br>".join(",",$pickedItems)."<br>";
echo "<b>Chosen Items:</b><br>";
echo "<table border cellspacing=0>";
echo "<tr><td>Item</td><td>Value</td><td>Weight</td></tr>";
$totalVal = $totalWt = 0;
foreach($pickedItems as $key) {
$totalVal += $v4[$key];
$totalWt += $w4[$key];

View file

@ -0,0 +1,36 @@
def total_value(items, max_weight):
return sum([x[2] for x in items]) if sum([x[1] for x in items]) < max_weight else 0
cache = {}
def solve(items, max_weight):
if not items:
return ()
if (items,max_weight) not in cache:
head = items[0]
tail = items[1:]
include = (head,) + solve(tail, max_weight - head[1])
dont_include = solve(tail, max_weight)
if total_value(include, max_weight) > total_value(dont_include, max_weight):
answer = include
else:
answer = dont_include
cache[(items,max_weight)] = answer
return cache[(items,max_weight)]
items = (
("map", 9, 150), ("compass", 13, 35), ("water", 153, 200), ("sandwich", 50, 160),
("glucose", 15, 60), ("tin", 68, 45), ("banana", 27, 60), ("apple", 39, 40),
("cheese", 23, 30), ("beer", 52, 10), ("suntan cream", 11, 70), ("camera", 32, 30),
("t-shirt", 24, 15), ("trousers", 48, 10), ("umbrella", 73, 40),
("waterproof trousers", 42, 70), ("waterproof overclothes", 43, 75),
("note-case", 22, 80), ("sunglasses", 7, 20), ("towel", 18, 12),
("socks", 4, 50), ("book", 30, 10),
)
max_weight = 400
solution = solve(items, max_weight)
print "items:"
for x in solution:
print x[0]
print "value:", total_value(solution, max_weight)
print "weight:", sum([x[1] for x in solution])

View file

@ -1,4 +1,4 @@
/*REXX pgm solves a knapsack problem (22 items with weight restriction).*/
/*REXX program solves a knapsack problem (22 items with a weight restriction).*/
@.=; @.1 = 'map 9 150'
@.2 = 'compass 13 35'
@.3 = 'water 153 200'
@ -21,8 +21,8 @@
@.20 = 'towel 18 12'
@.21 = 'socks 4 50'
@.22 = 'book 30 10'
maxWeight=400 /*the maximum weight for knapsack*/
say; say 'maximum weight allowed for a knapsack:' comma(maxWeight); say
maxWeight=400 /*maximum weight for the knapsack*/
say; say 'maximum weight allowed for a knapsack:' commas(maxWeight); say
maxL=length('item') /*maximum width for table names. */
maxL=length('knapsack items') /*maximum width for table names. */
maxW=length('weight') /* " " " " weights*/
@ -30,53 +30,58 @@ maxV=length('value') /* " " " " values.*/
maxQ=length('pieces') /* " " " " quant. */
highQ=0 /*max quantity specified (if any)*/
items=0; i.=; w.=0; v.=0; q.=0; Tw=0; Tv=0; Tq=0 /*initialize stuff.*/
/*────────────────────────────────sort the choices by decreasing weight.*/
/*this minimizes # combinations. */
/*════════════════════════════════sort the choices by decreasing weight.*/
do j=1 while @.j\=='' /*process each choice and sort. */
_=@.j; _wt=word(_,2) /*choose first item (arbitrary). */
_=space(@.j) _wt=word(_,2) /*choose first item (arbitrary). */
_wt=word(_,2)
do k=j+1 while @.k\=='' /*find a possible heavier item. */
?wt=word(@.k,2)
if ?wt>_wt then do; _=@.k; @.k=@.j; @.j=_; _wt=?wt; end
end /*k*/
end /*j*/
obj=j-1 /*adjust for the DO loop index. */
/*────────────────────────────────build list of choices.────────────────*/
end /*j*/ /*adjust for the DO loop index.*/
obj=j-1
/*════════════════════════════════build list of choices.════════════════*/
do j=1 for obj /*build a list of choices. */
_=space(@.j) /*remove superfluous blanks. */
parse var _ item w v q . /*parse original choice for table*/
parse var @.j item w v q . /*parse original choice for table*/
if w>maxWeight then iterate /*if the weight > maximum, ignore*/
Tw=Tw+w; Tv=Tv+v; Tq=Tq+1 /*add totals up (for alignment). */
maxL=max(maxL,length(item)) /*find maximum width for item. */
if q=='' then q=1
highQ=max(highQ,q)
items=items+1 /*bump the item counter. */
items=items+1 /*bump # items.*/
i.items=item; w.items=w; v.items=v; q.items=q
do k=2 to q; items=items+1 /*bump the item counter. */
i.items=item; w.items=w; v.items=v; q.items=q
Tw=Tw+w; Tv=Tv+v; Tq=Tq+1
do k=2 to q; items=items+1 /*bump # items.*/
i.items=item; w.items=w; v.items=v; q.items=q
Tw=Tw+w; Tv=Tv+v; Tq=Tq+1
end /*k*/
end /*j*/
maxW=max(maxW,length(comma(Tw))) /*find maximum width for weight. */
maxV=max(maxV,length(comma(Tv))) /* " " " " value. */
maxQ=max(maxQ,length(comma(Tq))) /* " " " " quantity*/
maxW=max(maxW,length(commas(Tw))) /*find maximum width for weight. */
maxV=max(maxV,length(commas(Tv))) /* " " " " value. */
maxQ=max(maxQ,length(commas(Tq))) /* " " " " quantity*/
maxL=maxL+maxL%4+4 /*extend width of name for table.*/
/*────────────────────────────────show the list of choices.─────────────*/
/*════════════════════════════════show the list of choices.═════════════*/
call hdr 'item'; do j=1 for obj /*show all choices, nice format. */
parse var @.j item weight value q .
if highq==1 then q=
else if q=='' then q=1
call show item,weight,value,q
call show item, weight, value, q
end /*j*/
say; say 'number of items:' items; say
/*─────────────────────────────────────examine all the possible choices.*/
/*═════════════════════════════════════examine all the possible choices.*/
h=items; ho=h+1; m=maxWeight; $=0; call sim22
/*─────────────────────────────────────show the best choice (weight,val)*/
do h-1; ?=strip(strip(?),"L",0); end
/*═════════════════════════════════════show the best choice (weight,val)*/
do h-1; ?=strip(strip(?),"L",0); end
bestC=?; bestW=0; bestV=$; highQ=0; totP=words(bestC)
call hdr 'best choice'
do j=1 to totP /*J is modified within DO loop. */
_=word(bestC,j); _w=w._; _v=v._; q=1
if _==0 then iterate
@ -85,38 +90,35 @@ call hdr 'best choice'
j=j+1; w._=w._+_w; v._=v._+_v; q=q+1
end /*k*/
call show i._,w._,v._,q; bestW=bestw+w._
end /*j*/
end /*j*/
call hdr2; say
call show 'best weight' ,bestW /*show a nicely formatted winnerW*/
call show 'best value' ,,bestV /*show a nicely formatted winnerV*/
call show 'knapsack items',,,totP /*show a nicely formatted pieces.*/
exit /*stick a fork in it, we're done.*/
/*────────────────────────────────COMMA subroutine───────────────────────────────────────────────*/
comma: procedure; parse arg _,c,p,t;arg ,cu;c=word(c ",",1);if cu=='BLANK' then c=' ';o=word(p 3,1)
k=0;p=abs(o);t=word(t 999999999,1);if \datatype(p,'W')|\datatype(t,'W')|p==0|arg()>4 then return _
n=_'.9'; #=123456789; if o<0 then do; b=verify(_,' '); if b==0 then return _
e=length(_)-verify(reverse(_),' ')+1; end; else do; b=verify(n,#,"M")
e=verify(n,#'0',,verify(n,#"0.",'M'))-p-1;end;do j=e to b by -p while k<t;_=insert(c,_,j);k=k+1;end
return _ /* [↑] adds commas to the 1st number found in the string.*/
/*────────────────────────────────HDR subroutine─────────────────────────────────────────────────*/
hdr: parse arg _item_,_; if highq\==1 then _=center('pieces',maxq)
call show center(_item_ ,maxL), center('weight',maxW), center('value',maxV), center(_,maxQ)
call hdr2; return
/*────────────────────────────────HDR2 subroutine────────────────────────────────────────────────*/
call show 'best weight' ,bestW /*show a nicely formatted winnerW. */
call show 'best value' ,,bestV /*show a nicely formatted winnerV. */
call show 'knapsack items',,,totP /*show a nicely formatted pieces. */
exit /*stick a fork in it, we're all done. */
/*────────────────────────────────────────────────────────────────────────────*/
commas: procedure; parse arg _; n=_'.9'; #=123456789; b=verify(n,#,"M")
e=verify(n,#'0',,verify(n,#"0.",'M'))-4
do j=e to b by -3; _=insert(',',_,j); end /*j*/; return _
/*────────────────────────────────────────────────────────────────────────────────────────*/
hdr: parse arg _item_,_; if highq\==1 then _=center('pieces',maxq)
call show center(_item_,maxL),center('weight',maxW),center('value',maxV),center(_,maxQ)
call hdr2; return
/*────────────────────────────────────────────────────────────────────────────*/
hdr2: _=maxQ; if highq==1 then _=0
call show copies('=',maxL),copies('=',maxW),copies('=',maxV),copies('=',_)
return
/*────────────────────────────────J? subroutine────────────────────────────────────────*/
call show copies('',maxL),copies('',maxW),copies('',maxV),copies('',_)
return
/*─────────────────────────────────────────────────────────────────────────────────────*/
j?: parse arg _,?; $=value('V'_); do j=1 for _; ?=? value('J'j); end; return
/*────────────────────────────────SHOW subroutine───────────────────────*/
/*────────────────────────────────────────────────────────────────────────────*/
show: parse arg _item,_weight,_value,_quant
say translate(left(_item,maxL,''),,'_'),
right(comma(_weight),maxW),
right(comma(_value ),maxV),
right(comma(_quant ),maxQ)
return
/*────────────────────────────────SIM22 subroutine───────────────────────────────────────────────────────────*/
sim22: do j1=0 for h+1; w1=w.j1; v1 = v.j1; if v1>$ then call j? 1
say translate(left(_item,maxL,''),,'_') right(commas(_weight),maxW),
right(commas(_value ),maxV),
right(commas(_quant ),maxQ)
return
/*───────────────────────────────────────────────────────────────────────────────────────────────────────────*/
sim22:
do j1 =0 for h+1; w1 = w.j1; v1 = v.j1; if v1>$ then call j? 1
do j2 =j1 +(j1 \==0) to h;if w.j2 +w1>m then iterate j1; w2 =w1 +w.j2; v2 =v1 +v.j2; if v2>$ then call j? 2
do j3 =j2 +(j2 \==0) to h;if w.j3 +w2>m then iterate j2; w3 =w2 +w.j3; v3 =v2 +v.j3; if v3>$ then call j? 3
do j4 =j3 +(j3 \==0) to h;if w.j4 +w3>m then iterate j3; w4 =w3 +w.j4; v4 =v3 +v.j4; if v4>$ then call j? 4
@ -138,5 +140,5 @@ sim22: do j1=0 for h+1; w1=w.j1; v1 =
do j20=j19+(j19\==0) to h;if w.j20+w19>m then iterate j19;w20=w19+w.j20;v20=v19+v.j20;if v20>$ then call j? 20
do j21=j20+(j20\==0) to h;if w.j21+w20>m then iterate j20;w21=w20+w.j21;v21=v20+v.j21;if v21>$ then call j? 21
do j22=j21+(j21\==0) to h;if w.j22+w21>m then iterate j21;w22=w21+w.j22;v22=v21+v.j22;if v22>$ then call j? 22
end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end
end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end
return

View file

@ -1,140 +1,134 @@
extern crate std;
#![feature(iter_arith)]
use std::cmp::max;
use std::vec::Vec;
// This struct is used to store our items that we want in our knap-sack.
struct Want<'a> {
#[derive(Clone, Debug)]
struct Item<'a> {
name: &'a str,
weight: uint,
value: uint
weight: usize,
value: usize
}
// Global, immutable allocation of our items.
static items : &'static [Want<'static>] = &[
Want {name: "map", weight: 9, value: 150},
Want {name: "compass", weight: 13, value: 35},
Want {name: "water", weight: 153, value: 200},
Want {name: "sandwich", weight: 50, value: 160},
Want {name: "glucose", weight: 15, value: 60},
Want {name: "tin", weight: 68, value: 45},
Want {name: "banana", weight: 27, value: 60},
Want {name: "apple", weight: 39, value: 40},
Want {name: "cheese", weight: 23, value: 30},
Want {name: "beer", weight: 52, value: 10},
Want {name: "suntancream", weight: 11, value: 70},
Want {name: "camera", weight: 32, value: 30},
Want {name: "T-shirt", weight: 24, value: 15},
Want {name: "trousers", weight: 48, value: 10},
Want {name: "umbrella", weight: 73, value: 40},
Want {name: "waterproof trousers", weight: 42, value: 70},
Want {name: "waterproof overclothes", weight: 43, value: 75},
Want {name: "note-case", weight: 22, value: 80},
Want {name: "sunglasses", weight: 7, value: 20},
Want {name: "towel", weight: 18, value: 12},
Want {name: "socks", weight: 4, value: 50},
Want {name: "book", weight: 30, value: 10}
];
// This is a bottom-up dynamic programming solution to the 0-1 knap-sack problem.
// maximize value
// subject to weights <= max_weight
fn knap_01_dp<'a>(xs: &[Want<'a>], max_weight: uint) -> Vec<Want<'a>> {
// Save this value, so we don't have to make repeated calls.
let xs_len = xs.len();
fn knapsack01_dyn<'a>(items: &[Item<'a>], max_weight: usize) -> Vec<Item<'a>> {
// Imagine we wrote a recursive function(item, max_weight) that returns a
// uint corresponding to the maximum cumulative value by considering a
// usize corresponding to the maximum cumulative value by considering a
// subset of items such that the combined weight <= max_weight.
//
// fn best_value(item: uint, max_weight: uint) -> uint{
// fn best_value(item: usize, max_weight: usize) -> usize {
// if item == 0 {
// return 0;
// }
// if xs[item - 1].weight > max_weight {
// if items[item - 1].weight > max_weight {
// return best_value(item - 1, max_weight);
// }
// return max(best_value(item - 1, max_weight),
// best_value(item - 1, max_weight - xs[item - 1].weight)
// + xs[item - 1].value);
// best_value(item - 1, max_weight - items[item - 1].weight)
// + items[item - 1].value);
// }
// }
//
// best_value(xs_len, max_weight) is equal to the maximum value that we
// can add to the bag.
// best_value(n_items, max_weight) is equal to the maximum value that
// we can add to the bag.
//
// The problem with using this function is that it performs redundant
// calculations.
//
// The dynamic programming solution is to precompute all of the values we
// need and put them into a 2D array.
// The dynamic programming solution is to precompute all of the values
// we need and put them into a 2D array.
//
// In a similar vein, the top-down solution would be to memoize the
// function then compute the results on demand.
let zero_vec = Vec::from_elem(max_weight + 1, 0 as uint);
let mut best_value = Vec::from_elem(xs_len + 1, zero_vec);
let mut best_value = vec![vec![0usize; max_weight + 1]; items.len() + 1];
// loop over the items
for i in range(0, xs_len) {
// loop over the weights
for w in range(1, max_weight + 1) {
// do we have room in our knapsack?
if xs[i].weight > w {
// if we don't, then we'll say that the value doesn't change
// when considering this item
*best_value.get_mut(i + 1).get_mut(w) = best_value.get(i).get(w).clone();
} else {
// if we do, then we have to see if the value we gain by adding
// the item, given the weight, is better than not adding the item
*best_value.get_mut(i + 1).get_mut(w) =
max(best_value.get(i).get(w).clone(),
best_value.get(i).get(w - xs[i].weight) + xs[i].value);
}
// Loop over the items.
for (i, it) in items.iter().enumerate() {
// Loop over the weights.
for w in 1 .. max_weight + 1 {
best_value[i + 1][w] =
// do we have room in our knapsack?
if it.weight > w {
// if we don't, then we'll say that the value doesn't change
// when considering this item
best_value[i][w].clone()
} else {
// If we do, then we have to see if the value we gain by adding
// the item, given the weight, is better than not adding the item.
max(best_value[i][w].clone(), best_value[i][w - it.weight] + it.value)
}
}
}
// a variable representing the weight left in the bag
// A possibly over-allocated dynamically sized vector to push results to.
let mut result = Vec::with_capacity(items.len());
// Variable representing the weight left in the bag
let mut left_weight = max_weight.clone();
// a possibly over-allocated dynamically sized vector to push results to
let mut result = Vec::with_capacity(xs_len);
// we built up the solution space through a forward pass over the data,
// now we have to traverse backwards to get the solution
for i in range(1, xs_len+1).rev() {
// We can check if an item should be added to the knap-sack by comparing
// best_value with and without this item. If best_value added this
// item then so should we.
if best_value.get(i).get(left_weight) != best_value.get(i - 1).get(left_weight) {
result.push(xs[i - 1]);
// we remove the weight of the object from the remaining weight
// we can add to the bag
left_weight -= xs[i - 1].weight;
// We built up the solution space through a forward pass over the data,
// now we have to traverse backwards to get the solution.
for (i, it) in items.iter().enumerate().rev() {
// We can check if an item should be added to the knap-sack by
// comparing best_value with and without this item. If best_value
// added this item then so should we.
if best_value[i + 1][left_weight] != best_value[i][left_weight] {
result.push(it.clone());
// We remove the weight of the object from the remaining weight
// we can add to the bag.
left_weight -= it.weight;
}
}
return result;
result
}
fn main () {
let xs = knap_01_dp(items, 400);
const MAX_WEIGHT: usize = 400;
// Print the items. We have to reverse the order because we solved the
// problem backward.
for i in xs.iter().rev() {
println!("Item: {}, Weight: {}, Value: {}", i.name, i.weight, i.value);
// Static immutable allocation of our items.
static ITEMS: &'static [Item<'static>] = &[
// Too much repetition of field names here!
Item { name: "map", weight: 9, value: 150 },
Item { name: "compass", weight: 13, value: 35 },
Item { name: "water", weight: 153, value: 200 },
Item { name: "sandwich", weight: 50, value: 160 },
Item { name: "glucose", weight: 15, value: 60 },
Item { name: "tin", weight: 68, value: 45 },
Item { name: "banana", weight: 27, value: 60 },
Item { name: "apple", weight: 39, value: 40 },
Item { name: "cheese", weight: 23, value: 30 },
Item { name: "beer", weight: 52, value: 10 },
Item { name: "suntancream", weight: 11, value: 70 },
Item { name: "camera", weight: 32, value: 30 },
Item { name: "T-shirt", weight: 24, value: 15 },
Item { name: "trousers", weight: 48, value: 10 },
Item { name: "umbrella", weight: 73, value: 40 },
Item { name: "waterproof trousers", weight: 42, value: 70 },
Item { name: "waterproof overclothes", weight: 43, value: 75 },
Item { name: "note-case", weight: 22, value: 80 },
Item { name: "sunglasses", weight: 7, value: 20 },
Item { name: "towel", weight: 18, value: 12 },
Item { name: "socks", weight: 4, value: 50 },
Item { name: "book", weight: 30, value: 10 }
];
let items = knapsack01_dyn(ITEMS, MAX_WEIGHT);
// We reverse the order because we solved the problem backward.
for it in items.iter().rev() {
println!("{:?}", it);
}
// Print the sum of weights.
let weights = xs.iter().fold(0, |a, &b| a + b.weight);
println!("Total Weight: {}", weights);
// Print the sum of the values.
let values = xs.iter().fold(0, |a, &b| a + b.value);
println!("Total Value: {}", values);
let tot_weight: usize = items.iter().map(|w| w.weight).sum();
println!("Total weight: {}", tot_weight);
let tot_value: usize = items.iter().map(|w| w.value).sum();
println!("Total value: {}", tot_value);
}