September Morn Update
This commit is contained in:
parent
4e2d22a71d
commit
aac6731f2c
6856 changed files with 141342 additions and 21127 deletions
|
|
@ -0,0 +1,86 @@
|
|||
require "bit_array"
|
||||
|
||||
struct BitArray
|
||||
def clone
|
||||
BitArray.new(size).tap { |new| new.to_slice.copy_from (to_slice) }
|
||||
end
|
||||
end
|
||||
|
||||
record Item, name : String, weight : Int32, value : Int32
|
||||
|
||||
record Selection, mask : BitArray, cur_index : Int32, total_value : Int32
|
||||
|
||||
class Knapsack
|
||||
@threshold_value = 0
|
||||
@threshold_choice : Selection?
|
||||
getter checked_nodes = 0
|
||||
|
||||
def knapsack_step(taken, items, remaining_weight)
|
||||
if taken.total_value > @threshold_value
|
||||
@threshold_value = taken.total_value
|
||||
@threshold_choice = taken
|
||||
end
|
||||
candidate_index = items.index(taken.cur_index) { |item| item.weight <= remaining_weight }
|
||||
return nil unless candidate_index
|
||||
@checked_nodes += 1
|
||||
candidate = items[candidate_index]
|
||||
# candidate is a best of available items, so if we fill remaining value with it
|
||||
# and still don't reach the threshold, the branch is wrong
|
||||
return nil if taken.total_value + 1.0 * candidate.value / candidate.weight * remaining_weight < @threshold_value
|
||||
# now recursively check both variants
|
||||
mask = taken.mask.clone
|
||||
mask[candidate_index] = true
|
||||
knapsack_step Selection.new(mask, candidate_index + 1, taken.total_value + candidate.value), items, remaining_weight - candidate.weight
|
||||
mask = taken.mask.clone
|
||||
mask[candidate_index] = false
|
||||
knapsack_step Selection.new(mask, candidate_index + 1, taken.total_value), items, remaining_weight
|
||||
end
|
||||
|
||||
def select(items, max_weight)
|
||||
@checked_variants = 0
|
||||
# sort by descending relative value
|
||||
list = items.sort_by { |item| -1.0 * item.value / item.weight }
|
||||
# use heuristic of relative value as an initial estimate for branch&bounds
|
||||
w = max_weight
|
||||
heur_list = list.take_while { |item| w -= item.weight; w > 0 }
|
||||
nothing = Selection.new(BitArray.new(items.size), 0, 0)
|
||||
@threshold_value = heur_list.sum(&.value) - 1
|
||||
@threshold_choice = nothing
|
||||
knapsack_step(nothing, list, max_weight)
|
||||
selected = @threshold_choice.not_nil!
|
||||
result = [] of Item
|
||||
selected.mask.each_with_index { |v, i| result << list[i] if v }
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
possible = [
|
||||
Item.new("map", 9, 150),
|
||||
Item.new("compass", 13, 35),
|
||||
Item.new("water", 153, 200),
|
||||
Item.new("sandwich", 50, 160),
|
||||
Item.new("glucose", 15, 60),
|
||||
Item.new("tin", 68, 45),
|
||||
Item.new("banana", 27, 60),
|
||||
Item.new("apple", 39, 40),
|
||||
Item.new("cheese", 23, 30),
|
||||
Item.new("beer", 52, 10),
|
||||
Item.new("suntan cream", 11, 70),
|
||||
Item.new("camera", 32, 30),
|
||||
Item.new("T-shirt", 24, 15),
|
||||
Item.new("trousers", 48, 10),
|
||||
Item.new("umbrella", 73, 40),
|
||||
Item.new("waterproof trousers", 42, 70),
|
||||
Item.new("waterproof overclothes", 43, 75),
|
||||
Item.new("note-case", 22, 80),
|
||||
Item.new("sunglasses", 7, 20),
|
||||
Item.new("towel", 18, 12),
|
||||
Item.new("socks", 4, 50),
|
||||
Item.new("book", 30, 10),
|
||||
]
|
||||
|
||||
solver = Knapsack.new
|
||||
used = solver.select(possible, 400)
|
||||
puts "optimal choice: #{used.map(&.name)}"
|
||||
puts "total weight #{used.sum(&.weight)}, total value #{used.sum(&.value)}"
|
||||
puts "checked nodes: #{solver.checked_nodes}"
|
||||
57
Task/Knapsack-problem-0-1/Perl-6/knapsack-problem-0-1-2.pl6
Normal file
57
Task/Knapsack-problem-0-1/Perl-6/knapsack-problem-0-1-2.pl6
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
my $raw = qq:to/TABLE/;
|
||||
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
|
||||
suntancream 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
|
||||
TABLE
|
||||
|
||||
my (@name, @weight, @value);
|
||||
|
||||
for split(["\n", /\t+/], $raw, :skip-empty) -> $n,$w,$v {
|
||||
@name.push: $n;
|
||||
@weight.push: $w;
|
||||
@value.push: $v;
|
||||
}
|
||||
|
||||
my $max_weight = 400;
|
||||
my @p = [Nil xx $max_weight+2 ] xx @name;
|
||||
|
||||
sub optimal ($i, $w) {
|
||||
return [0, []] if $i < 0;
|
||||
return |@p[$i][$w] if @p[$i][$w];
|
||||
|
||||
if @weight[$i] > $w {
|
||||
@p[$i][$w] = optimal($i-1, $w);
|
||||
} else {
|
||||
my @x = optimal($i-1, $w);
|
||||
my @y = optimal($i-1, $w - @weight[$i]);
|
||||
|
||||
if (@x[0] > @y[0] + @value[$i] ) {
|
||||
@p[$i][$w] = @x;
|
||||
} else {
|
||||
@p[$i][$w] = @y[0] + @value[$i], [|@y[1], @name[$i]];
|
||||
}
|
||||
}
|
||||
return |@p[$i][$w]
|
||||
}
|
||||
|
||||
my @solution = optimal(-1+@name, $max_weight);
|
||||
say "@solution[0]: " ~ join ' ', @solution[1];
|
||||
|
|
@ -25,41 +25,35 @@ TABLE
|
|||
|
||||
my (@name, @weight, @value);
|
||||
for (split "\n", $raw) {
|
||||
for ([ split /\t+/ ]) {
|
||||
push @name, $_->[0];
|
||||
push @weight, $_->[1];
|
||||
push @value, $_->[2];
|
||||
}
|
||||
for ([ split /\t+/ ]) {
|
||||
push @name, $_->[0];
|
||||
push @weight, $_->[1];
|
||||
push @value, $_->[2];
|
||||
}
|
||||
}
|
||||
|
||||
my $max_weight = 400;
|
||||
my @p = (map([[0, []], map undef, 0 .. $max_weight], 0 .. $#name),
|
||||
[ map([0, []], 0 .. $max_weight + 1)]);
|
||||
my @p = map [map undef, 0 .. 1+$max_weight], 0 .. $#name;
|
||||
|
||||
sub optimal {
|
||||
my ($i, $w) = @_;
|
||||
my ($i, $w) = @_;
|
||||
return [0, []] if $i < 0;
|
||||
return $p[$i][$w] if $p[$i][$w];
|
||||
|
||||
if (!defined $p[$i][$w]) {
|
||||
if ($weight[$i] > $w) {
|
||||
$p[$i][$w] = optimal($i - 1, $w)
|
||||
} else {
|
||||
my $x = optimal($i - 1, $w);
|
||||
my $y = optimal($i - 1, $w - $weight[$i]);
|
||||
if ($weight[$i] > $w) {
|
||||
$p[$i][$w] = optimal($i - 1, $w)
|
||||
} else {
|
||||
my $x = optimal($i - 1, $w);
|
||||
my $y = optimal($i - 1, $w - $weight[$i]);
|
||||
|
||||
if ($x->[0] > $y->[0] + $value[$i]) {
|
||||
$p[$i][$w] = $x
|
||||
} else {
|
||||
$p[$i][$w] = [ $y->[0] + $value[$i],
|
||||
[ @{$y->[1]}, $name[$i] ]]
|
||||
}
|
||||
}
|
||||
if ($x->[0] > $y->[0] + $value[$i]) {
|
||||
$p[$i][$w] = $x
|
||||
} else {
|
||||
$p[$i][$w] = [ $y->[0] + $value[$i], [ @{$y->[1]}, $name[$i] ]]
|
||||
}
|
||||
return $p[$i][$w]
|
||||
}
|
||||
return $p[$i][$w]
|
||||
}
|
||||
|
||||
my $sol = optimal($#name, $max_weight);
|
||||
print "$sol->[0]: @{$sol->[1]}\n";
|
||||
|
||||
# prints:
|
||||
# 1030: map compass water sandwich glucose banana suntancream waterproof trousers
|
||||
# waterproof overclothes note-case sunglasses socks
|
||||
my $solution = optimal($#name, $max_weight);
|
||||
print "$solution->[0]: @{$solution->[1]}\n";
|
||||
|
|
|
|||
60
Task/Knapsack-problem-0-1/Swift/knapsack-problem-0-1.swift
Normal file
60
Task/Knapsack-problem-0-1/Swift/knapsack-problem-0-1.swift
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
struct KnapsackItem {
|
||||
var name: String
|
||||
var weight: Int
|
||||
var value: Int
|
||||
}
|
||||
|
||||
func knapsack(items: [KnapsackItem], limit: Int) -> [KnapsackItem] {
|
||||
var table = Array(repeating: Array(repeating: 0, count: limit + 1), count: items.count + 1)
|
||||
|
||||
for j in 1..<items.count+1 {
|
||||
let item = items[j-1]
|
||||
|
||||
for w in 1..<limit+1 {
|
||||
if item.weight > w {
|
||||
table[j][w] = table[j-1][w]
|
||||
} else {
|
||||
table[j][w] = max(table[j-1][w], table[j-1][w-item.weight] + item.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var result = [KnapsackItem]()
|
||||
var w = limit
|
||||
|
||||
for j in stride(from: items.count, to: 0, by: -1) where table[j][w] != table[j-1][w] {
|
||||
let item = items[j-1]
|
||||
|
||||
result.append(item)
|
||||
|
||||
w -= item.weight
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
let items = [
|
||||
KnapsackItem(name: "map", weight: 9, value: 150), KnapsackItem(name: "compass", weight: 13, value: 35),
|
||||
KnapsackItem(name: "water", weight: 153, value: 200), KnapsackItem(name: "sandwich", weight: 50, value: 160),
|
||||
KnapsackItem(name: "glucose", weight: 15, value: 60), KnapsackItem(name: "tin", weight: 68, value: 45),
|
||||
KnapsackItem(name: "banana", weight: 27, value: 60), KnapsackItem(name: "apple", weight: 39, value: 40),
|
||||
KnapsackItem(name: "cheese", weight: 23, value: 30), KnapsackItem(name: "beer", weight: 52, value: 10),
|
||||
KnapsackItem(name: "suntan cream", weight: 11, value: 70), KnapsackItem(name: "camera", weight: 32, value: 30),
|
||||
KnapsackItem(name: "t-shirt", weight: 24, value: 15), KnapsackItem(name: "trousers", weight: 48, value: 10),
|
||||
KnapsackItem(name: "umbrella", weight: 73, value: 40), KnapsackItem(name: "waterproof trousers", weight: 42, value: 70),
|
||||
KnapsackItem(name: "waterproof overclothes", weight: 43, value: 75), KnapsackItem(name: "note-case", weight: 22, value: 80),
|
||||
KnapsackItem(name: "sunglasses", weight: 7, value: 20), KnapsackItem(name: "towel", weight: 18, value: 12),
|
||||
KnapsackItem(name: "socks", weight: 4, value: 50), KnapsackItem(name: "book", weight: 30, value: 10)
|
||||
]
|
||||
|
||||
let kept = knapsack(items: items, limit: 400)
|
||||
|
||||
print("Kept: ")
|
||||
|
||||
for item in kept {
|
||||
print(" \(item.name)")
|
||||
}
|
||||
|
||||
let (tValue, tWeight) = kept.reduce((0, 0), { ($0.0 + $1.value, $0.1 + $1.weight) })
|
||||
|
||||
print("For a total value of \(tValue) and a total weight of \(tWeight)")
|
||||
Loading…
Add table
Add a link
Reference in a new issue