Knapsack problem/Bounded: Difference between revisions
Content added Content deleted
m (Tidied up repaired python non-zero-one solution. Sorry, should have done this in a single edit!) |
Thundergnat (talk | contribs) (Rename Perl 6 -> Raku, alphabetize, minor clean-up) |
||
Line 309: | Line 309: | ||
socks 1 4 50 |
socks 1 4 50 |
||
count, weight, value: 14 396 1010</pre> |
count, weight, value: 14 396 1010</pre> |
||
=={{header|C sharp|C#}}== |
|||
Similar to Knapsack/0-1. |
|||
<lang csharp>using System; // 4790@3.6 |
|||
class program |
|||
{ |
|||
static void Main() |
|||
{ |
|||
knapSack(40); |
|||
var sw = System.Diagnostics.Stopwatch.StartNew(); |
|||
Console.Write(knapSack(400) + "\n" + sw.Elapsed); // 51 µs |
|||
Console.Read(); |
|||
} |
|||
static string knapSack(uint w1) |
|||
{ |
|||
init(); change(); |
|||
uint n = (uint)w.Length; var K = new uint[n + 1, w1 + 1]; |
|||
for (uint vi, wi, w0, x, i = 0; i < n; i++) |
|||
for (vi = v[i], wi = w[i], w0 = 1; w0 <= w1; w0++) |
|||
{ |
|||
x = K[i, w0]; |
|||
if (wi <= w0) x = max(vi + K[i, w0 - wi], x); |
|||
K[i + 1, w0] = x; |
|||
} |
|||
string str = ""; |
|||
for (uint v1 = K[n, w1]; v1 > 0; n--) |
|||
if (v1 != K[n - 1, w1]) |
|||
{ |
|||
v1 -= v[n - 1]; w1 -= w[n - 1]; str += items[n - 1] + "\n"; |
|||
} |
|||
return str; |
|||
} |
|||
static uint max(uint a, uint b) { return a > b ? a : b; } |
|||
static byte[] w, v; static string[] items; |
|||
static byte[] p = { 1, 1, 2, 2, 2, 3, 3, 3, 1, 3, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2 }; |
|||
static void init() |
|||
{ |
|||
w = new byte[] { 9, 13, 153, 50, 15, 68, 27, 39, 23, 52, 11, |
|||
32, 24, 48, 73, 42, 43, 22, 7, 18, 4, 30 }; |
|||
v = new byte[] { 150, 35, 200, 60, 60, 45, 60, 40, 30, 10, 70, |
|||
30, 15, 10, 40, 70, 75, 80, 20, 12, 50, 10 }; |
|||
items = new string[] {"map","compass","water","sandwich","glucose","tin", |
|||
"banana","apple","cheese","beer","suntan cream", |
|||
"camera","T-shirt","trousers","umbrella", |
|||
"waterproof trousers","waterproof overclothes", |
|||
"note-case","sunglasses","towel","socks","book"}; |
|||
} |
|||
static void change() |
|||
{ |
|||
int n = w.Length, s = 0, i, j, k; byte xi; |
|||
for (i = 0; i < n; i++) s += p[i]; |
|||
{ |
|||
byte[] x = new byte[s]; |
|||
for (k = i = 0; i < n; i++) |
|||
for (xi = w[i], j = p[i]; j > 0; j--) x[k++] = xi; |
|||
w = x; |
|||
} |
|||
{ |
|||
byte[] x = new byte[s]; |
|||
for (k = i = 0; i < n; i++) |
|||
for (xi = v[i], j = p[i]; j > 0; j--) x[k++] = xi; |
|||
v = x; |
|||
} |
|||
string[] pItems = new string[s]; string itemI; |
|||
for (k = i = 0; i < n; i++) |
|||
for (itemI = items[i], j = p[i]; j > 0; j--) pItems[k++] = itemI; |
|||
items = pItems; |
|||
} |
|||
}</lang> |
|||
=={{header|C++}}== |
=={{header|C++}}== |
||
Line 548: | Line 625: | ||
cout << "Weight: " << solution.w << " Value: " << solution.v << endl; |
cout << "Weight: " << solution.w << " Value: " << solution.v << endl; |
||
return 0; |
return 0; |
||
}</lang> |
|||
=={{header|C#}}== |
|||
Similar to Knapsack/0-1. |
|||
<lang csharp>using System; // 4790@3.6 |
|||
class program |
|||
{ |
|||
static void Main() |
|||
{ |
|||
knapSack(40); |
|||
var sw = System.Diagnostics.Stopwatch.StartNew(); |
|||
Console.Write(knapSack(400) + "\n" + sw.Elapsed); // 51 µs |
|||
Console.Read(); |
|||
} |
|||
static string knapSack(uint w1) |
|||
{ |
|||
init(); change(); |
|||
uint n = (uint)w.Length; var K = new uint[n + 1, w1 + 1]; |
|||
for (uint vi, wi, w0, x, i = 0; i < n; i++) |
|||
for (vi = v[i], wi = w[i], w0 = 1; w0 <= w1; w0++) |
|||
{ |
|||
x = K[i, w0]; |
|||
if (wi <= w0) x = max(vi + K[i, w0 - wi], x); |
|||
K[i + 1, w0] = x; |
|||
} |
|||
string str = ""; |
|||
for (uint v1 = K[n, w1]; v1 > 0; n--) |
|||
if (v1 != K[n - 1, w1]) |
|||
{ |
|||
v1 -= v[n - 1]; w1 -= w[n - 1]; str += items[n - 1] + "\n"; |
|||
} |
|||
return str; |
|||
} |
|||
static uint max(uint a, uint b) { return a > b ? a : b; } |
|||
static byte[] w, v; static string[] items; |
|||
static byte[] p = { 1, 1, 2, 2, 2, 3, 3, 3, 1, 3, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2 }; |
|||
static void init() |
|||
{ |
|||
w = new byte[] { 9, 13, 153, 50, 15, 68, 27, 39, 23, 52, 11, |
|||
32, 24, 48, 73, 42, 43, 22, 7, 18, 4, 30 }; |
|||
v = new byte[] { 150, 35, 200, 60, 60, 45, 60, 40, 30, 10, 70, |
|||
30, 15, 10, 40, 70, 75, 80, 20, 12, 50, 10 }; |
|||
items = new string[] {"map","compass","water","sandwich","glucose","tin", |
|||
"banana","apple","cheese","beer","suntan cream", |
|||
"camera","T-shirt","trousers","umbrella", |
|||
"waterproof trousers","waterproof overclothes", |
|||
"note-case","sunglasses","towel","socks","book"}; |
|||
} |
|||
static void change() |
|||
{ |
|||
int n = w.Length, s = 0, i, j, k; byte xi; |
|||
for (i = 0; i < n; i++) s += p[i]; |
|||
{ |
|||
byte[] x = new byte[s]; |
|||
for (k = i = 0; i < n; i++) |
|||
for (xi = w[i], j = p[i]; j > 0; j--) x[k++] = xi; |
|||
w = x; |
|||
} |
|||
{ |
|||
byte[] x = new byte[s]; |
|||
for (k = i = 0; i < n; i++) |
|||
for (xi = v[i], j = p[i]; j > 0; j--) x[k++] = xi; |
|||
v = x; |
|||
} |
|||
string[] pItems = new string[s]; string itemI; |
|||
for (k = i = 0; i < n; i++) |
|||
for (itemI = items[i], j = p[i]; j > 0; j--) pItems[k++] = itemI; |
|||
items = pItems; |
|||
} |
|||
}</lang> |
}</lang> |
||
Line 2,509: | Line 2,509: | ||
1 of socks |
1 of socks |
||
Value: 1010; Weight: 396</pre> |
Value: 1010; Weight: 396</pre> |
||
=={{header|Perl 6}}== |
|||
==== Original ==== |
|||
Recursive algorithm, with cache. Idiomatic code style, using multi-subs and a class. |
|||
{{works with|Rakudo|2017.01}} |
|||
<lang perl6>my class KnapsackItem { has $.name; has $.weight; has $.unit; } |
|||
multi sub pokem ([], $, $v = 0) { $v } |
|||
multi sub pokem ([$, *@], 0, $v = 0) { $v } |
|||
multi sub pokem ([$i, *@rest], $w, $v = 0) { |
|||
my $key = "{+@rest} $w $v"; |
|||
(state %cache){$key} or do { |
|||
my @skip = pokem @rest, $w, $v; |
|||
if $w >= $i.weight { # next one fits |
|||
my @put = pokem @rest, $w - $i.weight, $v + $i.unit; |
|||
return (%cache{$key} = |@put, $i.name).list if @put[0] > @skip[0]; |
|||
} |
|||
return (%cache{$key} = |@skip).list; |
|||
} |
|||
} |
|||
my $MAX_WEIGHT = 400; |
|||
my @table = flat map -> $name, $weight, $unit, $count { |
|||
KnapsackItem.new( :$name, :$weight, :$unit ) xx $count; |
|||
}, |
|||
'map', 9, 150, 1, |
|||
'compass', 13, 35, 1, |
|||
'water', 153, 200, 2, |
|||
'sandwich', 50, 60, 2, |
|||
'glucose', 15, 60, 2, |
|||
'tin', 68, 45, 3, |
|||
'banana', 27, 60, 3, |
|||
'apple', 39, 40, 3, |
|||
'cheese', 23, 30, 1, |
|||
'beer', 52, 10, 3, |
|||
'suntan cream', 11, 70, 1, |
|||
'camera', 32, 30, 1, |
|||
'T-shirt', 24, 15, 2, |
|||
'trousers', 48, 10, 2, |
|||
'umbrella', 73, 40, 1, |
|||
'waterproof trousers', 42, 70, 1, |
|||
'waterproof overclothes', 43, 75, 1, |
|||
'note-case', 22, 80, 1, |
|||
'sunglasses', 7, 20, 1, |
|||
'towel', 18, 12, 2, |
|||
'socks', 4, 50, 1, |
|||
'book', 30, 10, 2 |
|||
; |
|||
my ($value, @result) = pokem @table, $MAX_WEIGHT; |
|||
(my %hash){$_}++ for @result; |
|||
say "Value = $value"; |
|||
say "Tourist put in the bag:"; |
|||
say " # ITEM"; |
|||
for %hash.sort -> $item { |
|||
say " {$item.value} {$item.key}"; |
|||
}</lang> |
|||
{{out}} |
|||
<pre>Value = 1010 |
|||
Tourist put in the bag: |
|||
# ITEM |
|||
3 banana |
|||
1 cheese |
|||
1 compass |
|||
2 glucose |
|||
1 map |
|||
1 note-case |
|||
1 socks |
|||
1 sunglasses |
|||
1 suntan cream |
|||
1 water |
|||
1 waterproof overclothes</pre> |
|||
==== Faster alternative ==== |
|||
Also recursive, with cache, but substantially faster. Code more generic (ported from Perl solution). |
|||
<lang perl6>my $raw = qq:to/TABLE/; |
|||
map 9 150 1 |
|||
compass 13 35 1 |
|||
water 153 200 2 |
|||
sandwich 50 60 2 |
|||
glucose 15 60 2 |
|||
tin 68 45 3 |
|||
banana 27 60 3 |
|||
apple 39 40 3 |
|||
cheese 23 30 1 |
|||
beer 52 10 1 |
|||
suntancream 11 70 1 |
|||
camera 32 30 1 |
|||
T-shirt 24 15 2 |
|||
trousers 48 10 2 |
|||
umbrella 73 40 1 |
|||
w_trousers 42 70 1 |
|||
w_overcoat 43 75 1 |
|||
note-case 22 80 1 |
|||
sunglasses 7 20 1 |
|||
towel 18 12 2 |
|||
socks 4 50 1 |
|||
book 30 10 2 |
|||
TABLE |
|||
my @items; |
|||
for split(["\n", /\s+/], $raw, :skip-empty) -> $n,$w,$v,$q { |
|||
@items.push: %{ name => $n, weight => $w, value => $v, quant => $q} |
|||
} |
|||
my $max_weight = 400; |
|||
sub pick ($weight, $pos) { |
|||
state %cache; |
|||
return 0, 0 if $pos < 0 or $weight <= 0; |
|||
my $key = $weight ~ $pos; |
|||
%cache{$key} or do { |
|||
my %item = @items[$pos]; |
|||
my ($bv, $bi, $bw, @bp) = (0, 0, 0); |
|||
for 0 .. %item{'quant'} -> $i { |
|||
last if $i * %item{'weight'} > $weight; |
|||
my ($v, $w, @p) = pick($weight - $i * %item{'weight'}, $pos - 1); |
|||
next if ($v += $i * %item{'value'}) <= $bv; |
|||
($bv, $bi, $bw, @bp) = ($v, $i, $w, |@p); |
|||
} |
|||
%cache{$key} = $bv, $bw + $bi * %item{'weight'}, |@bp, $bi; |
|||
} |
|||
} |
|||
my ($v, $w, @p) = pick($max_weight, @items.end); |
|||
{ say "{@p[$_]} of @items[$_]{'name'}" if @p[$_] } for 0 .. @p.end; |
|||
say "Value: $v Weight: $w";</lang> |
|||
{{out}} |
|||
<pre>1 of map |
|||
1 of compass |
|||
1 of water |
|||
2 of glucose |
|||
3 of banana |
|||
1 of cheese |
|||
1 of suntancream |
|||
1 of w_overcoat |
|||
1 of note-case |
|||
1 of sunglasses |
|||
1 of socks |
|||
Value: 1010 Weight: 396</pre> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
Line 3,606: | Line 3,461: | ||
(choice "map" 1))) |
(choice "map" 1))) |
||
</pre> |
</pre> |
||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
==== Original ==== |
|||
Recursive algorithm, with cache. Idiomatic code style, using multi-subs and a class. |
|||
{{works with|Rakudo|2017.01}} |
|||
<lang perl6>my class KnapsackItem { has $.name; has $.weight; has $.unit; } |
|||
multi sub pokem ([], $, $v = 0) { $v } |
|||
multi sub pokem ([$, *@], 0, $v = 0) { $v } |
|||
multi sub pokem ([$i, *@rest], $w, $v = 0) { |
|||
my $key = "{+@rest} $w $v"; |
|||
(state %cache){$key} or do { |
|||
my @skip = pokem @rest, $w, $v; |
|||
if $w >= $i.weight { # next one fits |
|||
my @put = pokem @rest, $w - $i.weight, $v + $i.unit; |
|||
return (%cache{$key} = |@put, $i.name).list if @put[0] > @skip[0]; |
|||
} |
|||
return (%cache{$key} = |@skip).list; |
|||
} |
|||
} |
|||
my $MAX_WEIGHT = 400; |
|||
my @table = flat map -> $name, $weight, $unit, $count { |
|||
KnapsackItem.new( :$name, :$weight, :$unit ) xx $count; |
|||
}, |
|||
'map', 9, 150, 1, |
|||
'compass', 13, 35, 1, |
|||
'water', 153, 200, 2, |
|||
'sandwich', 50, 60, 2, |
|||
'glucose', 15, 60, 2, |
|||
'tin', 68, 45, 3, |
|||
'banana', 27, 60, 3, |
|||
'apple', 39, 40, 3, |
|||
'cheese', 23, 30, 1, |
|||
'beer', 52, 10, 3, |
|||
'suntan cream', 11, 70, 1, |
|||
'camera', 32, 30, 1, |
|||
'T-shirt', 24, 15, 2, |
|||
'trousers', 48, 10, 2, |
|||
'umbrella', 73, 40, 1, |
|||
'waterproof trousers', 42, 70, 1, |
|||
'waterproof overclothes', 43, 75, 1, |
|||
'note-case', 22, 80, 1, |
|||
'sunglasses', 7, 20, 1, |
|||
'towel', 18, 12, 2, |
|||
'socks', 4, 50, 1, |
|||
'book', 30, 10, 2 |
|||
; |
|||
my ($value, @result) = pokem @table, $MAX_WEIGHT; |
|||
(my %hash){$_}++ for @result; |
|||
say "Value = $value"; |
|||
say "Tourist put in the bag:"; |
|||
say " # ITEM"; |
|||
for %hash.sort -> $item { |
|||
say " {$item.value} {$item.key}"; |
|||
}</lang> |
|||
{{out}} |
|||
<pre>Value = 1010 |
|||
Tourist put in the bag: |
|||
# ITEM |
|||
3 banana |
|||
1 cheese |
|||
1 compass |
|||
2 glucose |
|||
1 map |
|||
1 note-case |
|||
1 socks |
|||
1 sunglasses |
|||
1 suntan cream |
|||
1 water |
|||
1 waterproof overclothes</pre> |
|||
==== Faster alternative ==== |
|||
Also recursive, with cache, but substantially faster. Code more generic (ported from Perl solution). |
|||
<lang perl6>my $raw = qq:to/TABLE/; |
|||
map 9 150 1 |
|||
compass 13 35 1 |
|||
water 153 200 2 |
|||
sandwich 50 60 2 |
|||
glucose 15 60 2 |
|||
tin 68 45 3 |
|||
banana 27 60 3 |
|||
apple 39 40 3 |
|||
cheese 23 30 1 |
|||
beer 52 10 1 |
|||
suntancream 11 70 1 |
|||
camera 32 30 1 |
|||
T-shirt 24 15 2 |
|||
trousers 48 10 2 |
|||
umbrella 73 40 1 |
|||
w_trousers 42 70 1 |
|||
w_overcoat 43 75 1 |
|||
note-case 22 80 1 |
|||
sunglasses 7 20 1 |
|||
towel 18 12 2 |
|||
socks 4 50 1 |
|||
book 30 10 2 |
|||
TABLE |
|||
my @items; |
|||
for split(["\n", /\s+/], $raw, :skip-empty) -> $n,$w,$v,$q { |
|||
@items.push: %{ name => $n, weight => $w, value => $v, quant => $q} |
|||
} |
|||
my $max_weight = 400; |
|||
sub pick ($weight, $pos) { |
|||
state %cache; |
|||
return 0, 0 if $pos < 0 or $weight <= 0; |
|||
my $key = $weight ~ $pos; |
|||
%cache{$key} or do { |
|||
my %item = @items[$pos]; |
|||
my ($bv, $bi, $bw, @bp) = (0, 0, 0); |
|||
for 0 .. %item{'quant'} -> $i { |
|||
last if $i * %item{'weight'} > $weight; |
|||
my ($v, $w, @p) = pick($weight - $i * %item{'weight'}, $pos - 1); |
|||
next if ($v += $i * %item{'value'}) <= $bv; |
|||
($bv, $bi, $bw, @bp) = ($v, $i, $w, |@p); |
|||
} |
|||
%cache{$key} = $bv, $bw + $bi * %item{'weight'}, |@bp, $bi; |
|||
} |
|||
} |
|||
my ($v, $w, @p) = pick($max_weight, @items.end); |
|||
{ say "{@p[$_]} of @items[$_]{'name'}" if @p[$_] } for 0 .. @p.end; |
|||
say "Value: $v Weight: $w";</lang> |
|||
{{out}} |
|||
<pre>1 of map |
|||
1 of compass |
|||
1 of water |
|||
2 of glucose |
|||
3 of banana |
|||
1 of cheese |
|||
1 of suntancream |
|||
1 of w_overcoat |
|||
1 of note-case |
|||
1 of sunglasses |
|||
1 of socks |
|||
Value: 1010 Weight: 396</pre> |
|||
=={{header|REXX}}== |
=={{header|REXX}}== |