Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -1,4 +1,9 @@
A tourist wants to make a good trip at the weekend with his friends. They will go to the mountains to see the wonders of nature, so he needs to pack well for the trip. He has a good knapsack for carrying things, but knows that he can carry a maximum of only 4kg in it and it will have to last the whole day. He creates a list of what he wants to bring for the trip but the total weight of all items is too much. He then decides to add columns to his initial list detailing their weights and a numerical value representing how important the item is for the trip.
{{omit from|GUISS}}
A tourist wants to make a good trip at the weekend with his friends.
They will go to the mountains to see the wonders of nature, so he needs to pack well for the trip.
He has a good knapsack for carrying things, but knows that he can carry a maximum of only 4kg in it and it will have to last the whole day.
He creates a list of what he wants to bring for the trip but the total weight of all items is too much.
He then decides to add columns to his initial list detailing their weights and a numerical value representing how important the item is for the trip.
Here is the list:
@ -54,9 +59,13 @@ Here is the list:
| knapsack || ≤400 dag || ?
|}
The tourist can choose to take any combination of items from the list, but only one of each item is available. He may not cut or diminish the items, so he can only take whole units of any item.
The tourist can choose to take any combination of items from the list,
but only one of each item is available.
He may not cut or diminish the items, so he can only take whole units of any item.
'''Which items does the tourist carry in his knapsack so that their total weight does not exceed 400 dag [4 kg], and their total value is maximised?'''
'''Which items does the tourist carry in his knapsack
so that their total weight does not exceed 400 dag [4 kg],
and their total value is maximised?'''
[dag = decagram = 10 grams]

View file

@ -1,4 +1,5 @@
---
category:
- Memoization
- Puzzles
note: Classic CS problems and programs

View file

@ -2,8 +2,8 @@ import std.stdio, std.algorithm, std.typecons, std.array, std.range;
struct Item { string name; int weight, value; }
Item[] knapsack01DinamicProgramming(in Item[] items, in int limit)
pure nothrow {
Item[] knapsack01DinamicProgramming(immutable Item[] items, in int limit)
pure nothrow @safe {
auto tab = new int[][](items.length + 1, limit + 1);
foreach (immutable i, immutable it; items)
@ -22,7 +22,7 @@ pure nothrow {
return result;
}
void main() {
void main() @safe {
enum int limit = 400;
immutable Item[] items = [
{"apple", 39, 40}, {"banana", 27, 60},

View file

@ -17,7 +17,8 @@ immutable Item[] items = [
struct Solution { uint bits; int value; }
static assert(items.length <= Solution.bits.sizeof * 8);
void solve(in int weight, in int idx, ref Solution s) pure nothrow {
void solve(in int weight, in int idx, ref Solution s)
pure nothrow @nogc @safe {
if (idx < 0) {
s.bits = s.value = 0;
return;
@ -38,8 +39,9 @@ void solve(in int weight, in int idx, ref Solution s) pure nothrow {
s = (v1.value >= v2.value) ? v1 : v2;
}
void main() {
void main() @safe {
import std.stdio;
auto s = Solution(0, 0);
solve(400, items.length - 1, s);
@ -50,5 +52,5 @@ void main() {
writeln(" ", it.name);
w += it.weight;
}
writeln("\nTotal value: %d; weight: %d", s.value, w);
writefln("\nTotal value: %d; weight: %d", s.value, w);
}

View file

@ -0,0 +1,202 @@
/*global portviz:false, _:false */
/*
* 0-1 knapsack solution, recursive, memoized, approximate.
*
* credits:
*
* the Go implementation here:
* http://rosettacode.org/mw/index.php?title=Knapsack_problem/0-1
*
* approximation details here:
* http://math.mit.edu/~goemans/18434S06/knapsack-katherine.pdf
*/
portviz.knapsack = {};
(function() {
this.combiner = function(items, weightfn, valuefn) {
// approximation guarantees result >= (1-e) * optimal
var _epsilon = 0.01;
var _p = _.max(_.map(items,valuefn));
var _k = _epsilon * _p / items.length;
var _memo = (function(){
var _mem = {};
var _key = function(i, w) {
return i + '::' + w;
};
return {
get: function(i, w) {
return _mem[_key(i,w)];
},
put: function(i, w, r) {
_mem[_key(i,w)]=r;
return r;
}
};
})();
var _m = function(i, w) {
i = Math.round(i);
w = Math.round(w);
if (i < 0 || w === 0) {
// empty base case
return {items: [], totalWeight: 0, totalValue: 0};
}
var mm = _memo.get(i,w);
if (!_.isUndefined(mm)) {
return mm;
}
var item = items[i];
if (weightfn(item) > w) {
//item does not fit, try the next item
return _memo.put(i, w, _m(i-1, w));
}
// this item could fit.
// are we better off excluding it?
var excluded = _m(i-1, w);
// or including it?
var included = _m(i-1, w - weightfn(item));
if (included.totalValue + Math.floor(valuefn(item)/_k) > excluded.totalValue) {
// better off including it
// make a copy of the list
var i1 = included.items.slice();
i1.push(item);
return _memo.put(i, w,
{items: i1,
totalWeight: included.totalWeight + weightfn(item),
totalValue: included.totalValue + Math.floor(valuefn(item)/_k)});
}
//better off excluding it
return _memo.put(i,w, excluded);
};
return {
/* one point */
one: function(maxweight) {
var scaled = _m(items.length - 1, maxweight);
return {
items: scaled.items,
totalWeight: scaled.totalWeight,
totalValue: scaled.totalValue * _k
};
},
/* the entire EF */
ef: function(maxweight, step) {
return _.map(_.range(0, maxweight+1, step), function(weight) {
var scaled = _m(items.length - 1, weight);
return {
items: scaled.items,
totalWeight: scaled.totalWeight,
totalValue: scaled.totalValue * _k
};
});
}
};
};
}).apply(portviz.knapsack);
/*global portviz:false, _:false */
/*
* after rosettacode.org/mw/index.php?title=Knapsack_problem/0-1
*/
var allwants = [
{name:"map", weight:9, value: 150},
{name:"compass", weight:13, value: 35},
{name:"water", weight:153, value: 200},
{name:"sandwich", weight: 50, value: 160},
{name:"glucose", weight:15, value: 60},
{name:"tin", weight:68, value: 45},
{name:"banana", weight:27, value: 60},
{name:"apple", weight:39, value: 40},
{name:"cheese", weight:23, value: 30},
{name:"beer", weight:52, value: 10},
{name:"suntan cream", weight:11, value: 70},
{name:"camera", weight:32, value: 30},
{name:"T-shirt", weight:24, value: 15},
{name:"trousers", weight:48, value: 10},
{name:"umbrella", weight:73, value: 40},
{name:"waterproof trousers", weight:42, value: 70},
{name:"waterproof overclothes", weight:43, value: 75},
{name:"note-case", weight:22, value: 80},
{name:"sunglasses", weight:7, value: 20},
{name:"towel", weight:18, value: 12},
{name:"socks", weight:4, value: 50},
{name:"book", weight:30, value: 10}
];
var near = function(actual, expected, tolerance) {
if (expected === 0 && actual === 0) return true;
if (expected === 0) {
return Math.abs(expected - actual) / actual < tolerance;
}
return Math.abs(expected - actual) / expected < tolerance;
};
test("one knapsack", function() {
var combiner =
portviz.knapsack.combiner(allwants,
function(x){return x.weight;},
function(x){return x.value;});
var oneport = combiner.one(400);
ok(near(oneport.totalValue, 1030, 0.01), "correct total value");
ok(near(oneport.totalValue, 1030, 0.01), "correct total value");
equal(oneport.totalWeight, 396, "correct total weight");
});
test("frontier", function() {
var combiner =
portviz.knapsack.combiner(allwants,
function(x){return x.weight;},
function(x){return x.value;});
var ef = combiner.ef(400, 1);
equal(ef.length, 401, "401 because it includes the endpoints");
ef = combiner.ef(400, 40);
equal(ef.length, 11, "11 because it includes the endpoints");
var expectedTotalValue = [
0,
330,
445,
590,
685,
755,
810,
860,
902,
960,
1030
] ;
_.each(ef, function(element, index) {
// 15% error! bleah!
ok(near(element.totalValue, expectedTotalValue[index], 0.15),
'actual ' + element.totalValue + ' expected ' + expectedTotalValue[index]);
});
deepEqual(_.pluck(ef, 'totalWeight'), [
0,
39,
74,
118,
158,
200,
236,
266,
316,
354,
396
]);
deepEqual(_.map(ef, function(x){return x.items.length;}), [
0,
4,
6,
7,
9,
10,
10,
12,
14,
11,
12
]);
});

View file

@ -0,0 +1,63 @@
global globalItems = #()
global usedMass = 0
global neededItems = #()
global totalValue = 0
struct kn_item
(
item, weight, value
)
itemStrings = #("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")
fn sortByValue a b =
(
if a[1].value > b[1].value then return -1
else
(
if a[1].value == b[1].value then return 0
else return 1
)
)
fn chooseBestItem maximumWeight: items: =
(
local itemsCopy = deepcopy items
local possibleItems = #()
for i = 1 to itemsCopy.count do
(
if itemsCopy[i].weight <= maximumWeight do append possibleItems (#(itemsCopy[i],i))
)
qsort possibleItems sortByValue
if possibleItems.count > 0 then return possibleItems[1] else return 0
)
for i = 1 to itemStrings.count do
(
local split = filterstring itemStrings[i] "#"
local itemStruct = kn_item item:split[1] weight:(split[2] as integer) \
value:(split[3] as integer)
appendifunique globalItems itemstruct
)
while usedMass < 400 do
(
local item = chooseBestItem maximumweight:(400-usedMass) items:(globalItems)
if item != 0 then
(
deleteitem globalItems (item[2])
appendifunique neededItems item[1]
usedMass += item[1].weight
) else exit
)
for i in neededitems do
(
format "Item name: %, weight: %, value:%\n" i.item i.weight i.value
totalValue += i.value
)
format "Total mass: %, Total Value: %\n" usedMass totalValue

View file

@ -0,0 +1,15 @@
Item name: water, weight: 153, value:200
Item name: sandwich, weight: 50, value:160
Item name: map, weight: 9, value:150
Item name: note-case, weight: 22, value:80
Item name: waterproof overclothes, weight: 43, value:75
Item name: suntan cream, weight: 11, value:70
Item name: waterproof trousers, weight: 42, value:70
Item name: glucose, weight: 15, value:60
Item name: banana, weight: 27, value:60
Item name: socks, weight: 4, value:50
Item name: compass, weight: 13, value:35
Item name: sunglasses, weight: 7, value:20
OK
Total mass: 396, Total Value: 1030
OK

View file

@ -1,27 +1,26 @@
/*REXX pgm solves a knapsack problem (22 items with weight restriction).*/
@.=
@.1 = 'map 9 150'
@.2 = 'compass 13 35'
@.3 = 'water 153 200'
@.4 = 'sandwich 50 160'
@.5 = 'glucose 15 60'
@.6 = 'tin 68 45'
@.7 = 'banana 27 60'
@.8 = 'apple 39 40'
@.9 = 'cheese 23 30'
@.10 = 'beer 52 10'
@.11 = 'suntan_cream 11 70'
@.12 = 'camera 32 30'
@.13 = 'T-shirt 24 15'
@.14 = 'trousers 48 10'
@.15 = 'umbrella 73 40'
@.16 = 'waterproof_trousers 42 70'
@.17 = 'waterproof_overclothes 43 75'
@.18 = 'note-case 22 80'
@.19 = 'sunglasses 7 20'
@.20 = 'towel 18 12'
@.21 = 'socks 4 50'
@.22 = 'book 30 10'
@.=; @.1 = 'map 9 150'
@.2 = 'compass 13 35'
@.3 = 'water 153 200'
@.4 = 'sandwich 50 160'
@.5 = 'glucose 15 60'
@.6 = 'tin 68 45'
@.7 = 'banana 27 60'
@.8 = 'apple 39 40'
@.9 = 'cheese 23 30'
@.10 = 'beer 52 10'
@.11 = 'suntan_cream 11 70'
@.12 = 'camera 32 30'
@.13 = 'T-shirt 24 15'
@.14 = 'trousers 48 10'
@.15 = 'umbrella 73 40'
@.16 = 'waterproof_trousers 42 70'
@.17 = 'waterproof_overclothes 43 75'
@.18 = 'note-case 22 80'
@.19 = 'sunglasses 7 20'
@.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
maxL=length('item') /*maximum width for table names. */
@ -53,7 +52,7 @@ obj=j-1 /*adjust for the DO loop index. */
highQ=max(highQ,q)
items=items+1 /*bump the item counter. */
i.items=item; w.items=w; v.items=v; q.items=q
do k=2 to q; items=items+1 /*bump the item counter. */
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
end /*k*/
@ -72,100 +71,72 @@ call hdr 'item'; do j=1 for obj /*show all choices, nice format. */
end /*j*/
say; say 'number of items:' items; say
/*─────────────────────────────────────examine 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
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
do k=j+1 to totP
__=word(bestC,k); if i._\==i.__ then leave
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*/
do j=1 to totP /*J is modified within DO loop. */
_=word(bestC,j); _w=w._; _v=v._; q=1
if _==0 then iterate
do k=j+1 to totP
__=word(bestC,k); if i._\==i.__ then leave
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*/
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);p=abs(o);t=word(t 999999999,1)
if \datatype(p,'W')|\datatype(t,'W')|p==0|arg()>4 then return _;n=_'.9'
#=123456789;k=0;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 _
/*────────────────────────────────HDR subroutine────────────────────────*/
/*────────────────────────────────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
call show center(_item_ ,maxL), center('weight',maxW), center('value',maxV), center(_,maxQ)
call hdr2; return
/*────────────────────────────────HDR2 subroutine────────────────────────────────────────────────*/
hdr2: _=maxQ; if highq==1 then _=0
call show copies('=',maxL),copies('=',maxW),copies('=',maxV),copies('=',_)
return
/*────────────────────────────────HDR2 subroutine───────────────────────*/
hdr2: _=maxQ; if highq==1 then _=0; call show copies('=' ,maxL),,
copies('=' ,maxW),,
copies('=' ,maxV),,
copies('=' ,_ )
return
/*────────────────────────────────J? subroutine─────────────────────────*/
j?: parse arg _,?; $=value('V'_); do j=1 for _; ?=? value('J'j); end; return
/*────────────────────────────────J? subroutine────────────────────────────────────────*/
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)
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
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
do j5=j4+(j4\==0) to h
if w.j5+w4>m then iterate j4;w5=w4+w.j5;v5=v4+v.j5;if v5>$ then call j? 5
do j6=j5+(j5\==0) to h
if w.j6+w5>m then iterate j5;w6=w5+w.j6;v6=v5+v.j6;if v6>$ then call j? 6
do j7=j6+(j6\==0) to h
if w.j7+w6>m then iterate j6;w7=w6+w.j7;v7=v6+v.j7;if v7>$ then call j? 7
do j8=j7+(j7\==0) to h
if w.j8+w7>m then iterate j7;w8=w7+w.j8;v8=v7+v.j8;if v8>$ then call j? 8
do j9=j8+(j8\==0) to h
if w.j9+w8>m then iterate j8;w9=w8+w.j9;v9=v8+v.j9;if v9>$ then call j? 9
do j10=j9+(j9\==0) to h
if w.j10+w9>m then iterate j9;w10=w9+w.j10;v10=v9+v.j10;if v10>$ then call j? 10
do j11=j10+(j10\==0) to h
if w.j11+w10>m then iterate j10;w11=w10+w.j11;v11=v10+v.j11;if v11>$ then call j? 11
do j12=j11+(j11\==0) to h
if w.j12+w11>m then iterate j11;w12=w11+w.j12;v12=v11+v.j12;if v12>$ then call j? 12
do j13=j12+(j12\==0) to h
if w.j13+w12>m then iterate j12;w13=w12+w.j13;v13=v12+v.j13;if v13>$ then call j? 13
do j14=j13+(j13\==0) to h
if w.j14+w13>m then iterate j13;w14=w13+w.j14;v14=v13+v.j14;if v14>$ then call j? 14
do j15=j14+(j14\==0) to h
if w.j15+w14>m then iterate j14;w15=w14+w.j15;v15=v14+v.j15;if v15>$ then call j? 15
do j16=j15+(j15\==0) to h
if w.j16+w15>m then iterate j15;w16=w15+w.j16;v16=v15+v.j16;if v16>$ then call j? 16
do j17=j16+(j16\==0) to h
if w.j17+w16>m then iterate j16;w17=w16+w.j17;v17=v16+v.j17;if v17>$ then call j? 17
do j18=j17+(j17\==0) to h
if w.j18+w17>m then iterate j17;w18=w17+w.j18;v18=v17+v.j18;if v18>$ then call j? 18
do j19=j18+(j18\==0) to h
if w.j19+w18>m then iterate j18;w19=w18+w.j19;v19=v18+v.j19;if v19>$ then call j? 19
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
/*────────────────────────────────SIM22 subroutine───────────────────────────────────────────────────────────*/
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
do j5 =j4 +(j4 \==0) to h;if w.j5 +w4>m then iterate j4; w5 =w4 +w.j5; v5 =v4 +v.j5; if v5>$ then call j? 5
do j6 =j5 +(j5 \==0) to h;if w.j6 +w5>m then iterate j5; w6 =w5 +w.j6; v6 =v5 +v.j6; if v6>$ then call j? 6
do j7 =j6 +(j6 \==0) to h;if w.j7 +w6>m then iterate j6; w7 =w6 +w.j7; v7 =v6 +v.j7; if v7>$ then call j? 7
do j8 =j7 +(j7 \==0) to h;if w.j8 +w7>m then iterate j7; w8 =w7 +w.j8; v8 =v7 +v.j8; if v8>$ then call j? 8
do j9 =j8 +(j8 \==0) to h;if w.j9 +w8>m then iterate j8; w9 =w8 +w.j9; v9 =v8 +v.j9; if v9>$ then call j? 9
do j10=j9 +(j9 \==0) to h;if w.j10+w9>m then iterate j9; w10=w9 +w.j10;v10=v9 +v.j10;if v10>$ then call j? 10
do j11=j10+(j10\==0) to h;if w.j11+w10>m then iterate j10;w11=w10+w.j11;v11=v10+v.j11;if v11>$ then call j? 11
do j12=j11+(j11\==0) to h;if w.j12+w11>m then iterate j11;w12=w11+w.j12;v12=v11+v.j12;if v12>$ then call j? 12
do j13=j12+(j12\==0) to h;if w.j13+w12>m then iterate j12;w13=w12+w.j13;v13=v12+v.j13;if v13>$ then call j? 13
do j14=j13+(j13\==0) to h;if w.j14+w13>m then iterate j13;w14=w13+w.j14;v14=v13+v.j14;if v14>$ then call j? 14
do j15=j14+(j14\==0) to h;if w.j15+w14>m then iterate j14;w15=w14+w.j15;v15=v14+v.j15;if v15>$ then call j? 15
do j16=j15+(j15\==0) to h;if w.j16+w15>m then iterate j15;w16=w15+w.j16;v16=v15+v.j16;if v16>$ then call j? 16
do j17=j16+(j16\==0) to h;if w.j17+w16>m then iterate j16;w17=w16+w.j17;v17=v16+v.j17;if v17>$ then call j? 17
do j18=j17+(j17\==0) to h;if w.j18+w17>m then iterate j17;w18=w17+w.j18;v18=v17+v.j18;if v18>$ then call j? 18
do j19=j18+(j18\==0) to h;if w.j19+w18>m then iterate j18;w19=w18+w.j19;v19=v18+v.j19;if v19>$ then call j? 19
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
return

View file

@ -1,16 +1,16 @@
KnapsackItem = Struct.new(:name, :weight, :value)
potential_items = [
KnapsackItem.new('map', 9, 150), KnapsackItem.new('compass', 13, 35),
KnapsackItem.new('water', 153, 200), KnapsackItem.new('sandwich', 50, 160),
KnapsackItem.new('glucose', 15, 60), KnapsackItem.new('tin', 68, 45),
KnapsackItem.new('banana', 27, 60), KnapsackItem.new('apple', 39, 40),
KnapsackItem.new('cheese', 23, 30), KnapsackItem.new('beer', 52, 10),
KnapsackItem.new('suntan cream', 11, 70), KnapsackItem.new('camera', 32, 30),
KnapsackItem.new('t-shirt', 24, 15), KnapsackItem.new('trousers', 48, 10),
KnapsackItem.new('umbrella', 73, 40), KnapsackItem.new('waterproof trousers', 42, 70),
KnapsackItem.new('waterproof overclothes', 43, 75), KnapsackItem.new('note-case', 22, 80),
KnapsackItem.new('sunglasses', 7, 20), KnapsackItem.new('towel', 18, 12),
KnapsackItem.new('socks', 4, 50), KnapsackItem.new('book', 30, 10),
KnapsackItem['map', 9, 150], KnapsackItem['compass', 13, 35],
KnapsackItem['water', 153, 200], KnapsackItem['sandwich', 50, 160],
KnapsackItem['glucose', 15, 60], KnapsackItem['tin', 68, 45],
KnapsackItem['banana', 27, 60], KnapsackItem['apple', 39, 40],
KnapsackItem['cheese', 23, 30], KnapsackItem['beer', 52, 10],
KnapsackItem['suntan cream', 11, 70], KnapsackItem['camera', 32, 30],
KnapsackItem['t-shirt', 24, 15], KnapsackItem['trousers', 48, 10],
KnapsackItem['umbrella', 73, 40], KnapsackItem['waterproof trousers', 42, 70],
KnapsackItem['waterproof overclothes', 43, 75], KnapsackItem['note-case', 22, 80],
KnapsackItem['sunglasses', 7, 20], KnapsackItem['towel', 18, 12],
KnapsackItem['socks', 4, 50], KnapsackItem['book', 30, 10],
]
knapsack_capacity = 400
@ -19,39 +19,25 @@ class Array
def power_set
yield [] if block_given?
self.inject([[]]) do |ps, elem|
r = []
ps.each do |i|
ps.each_with_object([]) do |i,r|
r << i
new_subset = i + [elem]
yield new_subset if block_given?
r << new_subset
end
r
end
end
end
maxval = 0
solutions = []
potential_items.power_set do |subset|
weight = subset.inject(0) {|w, elem| w += elem.weight}
next if weight > knapsack_capacity
value = subset.inject(0) {|v, elem| v += elem.value}
if value == maxval
solutions << subset
elsif value > maxval
maxval = value
solutions = [subset]
end
end
maxval, solutions = potential_items.power_set.group_by {|subset|
weight = subset.inject(0) {|w, elem| w + elem.weight}
weight>knapsack_capacity ? 0 : subset.inject(0){|v, elem| v + elem.value}
}.max
puts "value: #{maxval}"
solutions.each do |set|
items = []
wt = 0
wt, items = 0, []
set.each {|elem| wt += elem.weight; items << elem.name}
puts "weight: #{wt}"
puts "items: #{items.sort.join(',')}"
puts "items: #{items.join(',')}"
end

View file

@ -1,84 +1,63 @@
KnapsackItem = Struct.new(:name, :cost, :value)
KnapsackProblem = Struct.new(:items, :max_cost)
KnapsackItem = Struct.new(:name, :weight, :value)
def dynamic_programming_knapsack(problem)
num_items = problem.items.size
items = problem.items
max_cost = problem.max_cost
cost_matrix = zeros(num_items, max_cost+1)
def dynamic_programming_knapsack(items, max_weight)
num_items = items.size
cost_matrix = Array.new(num_items){Array.new(max_weight+1, 0)}
num_items.times do |i|
(max_cost + 1).times do |j|
if(items[i].cost > j)
(max_weight + 1).times do |j|
if(items[i].weight > j)
cost_matrix[i][j] = cost_matrix[i-1][j]
else
cost_matrix[i][j] = [cost_matrix[i-1][j], items[i].value + cost_matrix[i-1][j-items[i].cost]].max
cost_matrix[i][j] = [cost_matrix[i-1][j], items[i].value + cost_matrix[i-1][j-items[i].weight]].max
end
end
end
cost_matrix
used_items = get_used_items(items, cost_matrix)
[get_list_of_used_items_names(items, used_items), # used items names
items.zip(used_items).map{|item,used| item.weight*used}.inject(:+), # total weight
cost_matrix.last.last] # total value
end
def get_used_items(problem, cost_matrix)
def get_used_items(items, cost_matrix)
i = cost_matrix.size - 1
currentCost = cost_matrix[0].size - 1
marked = Array.new(cost_matrix.size, 0)
marked = cost_matrix.map{0}
while(i >= 0 && currentCost >= 0)
if(i == 0 && cost_matrix[i][currentCost] > 0 ) || (cost_matrix[i][currentCost] != cost_matrix[i-1][currentCost])
marked[i] = 1
currentCost -= problem.items[i].cost
currentCost -= items[i].weight
end
i -= 1
end
marked
end
def get_list_of_used_items_names(problem, cost_matrix)
items = problem.items
used_items = get_used_items(problem, cost_matrix)
result = []
used_items.each_with_index do |item,i|
if item > 0
result << items[i].name
end
end
result.sort.join(', ')
end
def zeros(rows, cols)
Array.new(rows) do |row|
Array.new(cols, 0)
end
def get_list_of_used_items_names(items, used_items)
items.zip(used_items).map{|item,used| item.name if used>0}.compact.join(', ')
end
if $0 == __FILE__
items = [
KnapsackItem['map' , 9, 150], KnapsackItem['compass' , 13, 35],
KnapsackItem['water' , 153, 200], KnapsackItem['sandwich' , 50, 160],
KnapsackItem['glucose' , 15, 60], KnapsackItem['tin' , 68, 45],
KnapsackItem['banana' , 27, 60], KnapsackItem['apple' , 39, 40],
KnapsackItem['cheese' , 23, 30], KnapsackItem['beer' , 52, 10],
KnapsackItem['suntan cream' , 11, 70], KnapsackItem['camera' , 32, 30],
KnapsackItem['t-shirt' , 24, 15], KnapsackItem['trousers' , 48, 10],
KnapsackItem['umbrella' , 73, 40], KnapsackItem['waterproof trousers', 42, 70],
KnapsackItem['waterproof overclothes', 43, 75], KnapsackItem['note-case' , 22, 80],
KnapsackItem['sunglasses' , 7, 20], KnapsackItem['towel' , 18, 12],
KnapsackItem['socks' , 4, 50], KnapsackItem['book' , 30, 10]
]
items = [
KnapsackItem.new('map' , 9 , 150) , KnapsackItem.new('compass' , 13 , 35) ,
KnapsackItem.new('water' , 153 , 200) , KnapsackItem.new('sandwich' , 50 , 160) ,
KnapsackItem.new('glucose' , 15 , 60) , KnapsackItem.new('tin' , 68 , 45) ,
KnapsackItem.new('banana' , 27 , 60) , KnapsackItem.new('apple' , 39 , 40) ,
KnapsackItem.new('cheese' , 23 , 30) , KnapsackItem.new('beer' , 52 , 10) ,
KnapsackItem.new('suntan cream' , 11 , 70) , KnapsackItem.new('camera' , 32 , 30) ,
KnapsackItem.new('t-shirt' , 24 , 15) , KnapsackItem.new('trousers' , 48 , 10) ,
KnapsackItem.new('umbrella' , 73 , 40) , KnapsackItem.new('waterproof trousers' , 42 , 70) ,
KnapsackItem.new('waterproof overclothes' , 43 , 75) , KnapsackItem.new('note-case' , 22 , 80) ,
KnapsackItem.new('sunglasses' , 7 , 20) , KnapsackItem.new('towel' , 18 , 12) ,
KnapsackItem.new('socks' , 4 , 50) , KnapsackItem.new('book' , 30 , 10)
]
problem = KnapsackProblem.new(items, 400)
cost_matrix = dynamic_programming_knapsack problem
names, weight, value = dynamic_programming_knapsack(items, 400)
puts
puts 'Dynamic Programming:'
puts
puts 'Found solution: ' + get_list_of_used_items_names(problem, cost_matrix)
puts 'With value: ' + cost_matrix.last.last.to_s
puts "Found solution: #{names}"
puts "total weight: #{weight}"
puts "total value: #{value}"
end

View file

@ -0,0 +1,140 @@
extern crate std;
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> {
name: &'a str,
weight: uint,
value: uint
}
// 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();
// Imagine we wrote a recursive function(item, max_weight) that returns a
// uint 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{
// if item == 0 {
// return 0;
// }
// if xs[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(xs_len, 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.
//
// 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);
// 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);
}
}
}
// a 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;
}
}
return result;
}
fn main () {
let xs = knap_01_dp(items, 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);
}
// 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);
}

View file

@ -10,7 +10,14 @@ object Knapsack extends App {
val tv:Set[Item]=>Int=ps=>(ps:\0)((a,b)=>a.value+b) //total value
val pis = (loi.toSet.subsets).toList.filterNot(_==Set())
val res = pis.map(ss=>Pair(ss,tw(ss)))
#[test]
fn test_dp_results() {
let dp_results = knap_01_dp(items, 400);
let dp_weights= dp_results.iter().fold(0, |a, &b| a + b.weight);
let dp_values = dp_results.iter().fold(0, |a, &b| a + b.value);
assert_eq!(dp_weights, 396);
assert_eq!(dp_values, 1030);
} val res = pis.map(ss=>Pair(ss,tw(ss)))
.filter(p=>p._2>350 && p._2<401).map(p=>Pair(p,tv(p._1)))
.sortWith((s,t)=>s._2.compareTo(t._2) < 0)
.last