A-M baby
This commit is contained in:
parent
764da6cbbb
commit
db842d013d
19005 changed files with 197040 additions and 7 deletions
33
Task/Knapsack-problem-Continuous/0DESCRIPTION
Normal file
33
Task/Knapsack-problem-Continuous/0DESCRIPTION
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
See also: [[Knapsack problem]] and [[wp:Continuous_knapsack_problem|Wikipedia]].
|
||||
|
||||
A robber burgles a butcher's shop, where he can select from some items. He knows the weights and prices of each items. Because he has a knapsack with 15 kg maximal capacity, he wants to select the items such that he would have his profit maximized. He may cut the items; the item has a reduced price after cutting that is proportional to the original price by the ratio of masses. That means: half of an item has half the price of the original.
|
||||
|
||||
This is the item list in the butcher's:
|
||||
|
||||
{| style="text-align: left; width: 80%;" border="4" cellpadding="2" cellspacing="2"
|
||||
|+ Table of potential knapsack items
|
||||
|- style="background-color: rgb(255, 204, 255);"
|
||||
! Item !! Weight (kg) !! Price (Value)
|
||||
|-
|
||||
| beef || 3.8 || 36
|
||||
|-
|
||||
| pork || 5.4 || 43
|
||||
|-
|
||||
| ham || 3.6 || 90
|
||||
|-
|
||||
| greaves || 2.4 || 45
|
||||
|-
|
||||
| flitch || 4.0 || 30
|
||||
|-
|
||||
| brawn || 2.5 || 56
|
||||
|-
|
||||
| welt || 3.7 || 67
|
||||
|-
|
||||
| salami || 3.0 || 95
|
||||
|-
|
||||
| sausage || 5.9 || 98
|
||||
|- style="background-color: rgb(255, 204, 255);"
|
||||
| Knapsack || <=15 kg || ?
|
||||
|}
|
||||
|
||||
'''Which items does the robber carry in his knapsack so that their total weight does not exceed 15 kg, and their total value is maximised?'''
|
||||
2
Task/Knapsack-problem-Continuous/1META.yaml
Normal file
2
Task/Knapsack-problem-Continuous/1META.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
note: Classic CS problems and programs
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
with Ada.Text_IO;
|
||||
with Ada.Strings.Unbounded;
|
||||
|
||||
procedure Knapsack_Continuous is
|
||||
package US renames Ada.Strings.Unbounded;
|
||||
|
||||
type Item is record
|
||||
Name : US.Unbounded_String;
|
||||
Weight : Float;
|
||||
Value : Positive;
|
||||
Taken : Float;
|
||||
end record;
|
||||
|
||||
function "<" (Left, Right : Item) return Boolean is
|
||||
begin
|
||||
return Float (Left.Value) / Left.Weight <
|
||||
Float (Right.Value) / Right.Weight;
|
||||
end "<";
|
||||
|
||||
type Item_Array is array (Positive range <>) of Item;
|
||||
|
||||
function Total_Weight (Items : Item_Array) return Float is
|
||||
Sum : Float := 0.0;
|
||||
begin
|
||||
for I in Items'Range loop
|
||||
Sum := Sum + Items (I).Weight * Items (I).Taken;
|
||||
end loop;
|
||||
return Sum;
|
||||
end Total_Weight;
|
||||
|
||||
function Total_Value (Items : Item_Array) return Float is
|
||||
Sum : Float := 0.0;
|
||||
begin
|
||||
for I in Items'Range loop
|
||||
Sum := Sum + Float (Items (I).Value) * Items (I).Taken;
|
||||
end loop;
|
||||
return Sum;
|
||||
end Total_Value;
|
||||
|
||||
procedure Solve_Knapsack_Continuous
|
||||
(Items : in out Item_Array;
|
||||
Weight_Limit : Float)
|
||||
is
|
||||
begin
|
||||
-- order items by value per weight unit
|
||||
Sorting : declare
|
||||
An_Item : Item;
|
||||
J : Natural;
|
||||
begin
|
||||
for I in Items'First + 1 .. Items'Last loop
|
||||
An_Item := Items (I);
|
||||
J := I - 1;
|
||||
while J in Items'Range and then Items (J) < An_Item loop
|
||||
Items (J + 1) := Items (J);
|
||||
J := J - 1;
|
||||
end loop;
|
||||
Items (J + 1) := An_Item;
|
||||
end loop;
|
||||
end Sorting;
|
||||
declare
|
||||
Rest : Float := Weight_Limit;
|
||||
begin
|
||||
for I in Items'Range loop
|
||||
if Items (I).Weight <= Rest then
|
||||
Items (I).Taken := Items (I).Weight;
|
||||
else
|
||||
Items (I).Taken := Rest;
|
||||
end if;
|
||||
Rest := Rest - Items (I).Taken;
|
||||
exit when Rest <= 0.0;
|
||||
end loop;
|
||||
end;
|
||||
end Solve_Knapsack_Continuous;
|
||||
|
||||
All_Items : Item_Array :=
|
||||
((US.To_Unbounded_String ("beef"), 3.8, 36, 0.0),
|
||||
(US.To_Unbounded_String ("pork"), 5.4, 43, 0.0),
|
||||
(US.To_Unbounded_String ("ham"), 3.6, 90, 0.0),
|
||||
(US.To_Unbounded_String ("greaves"), 2.4, 45, 0.0),
|
||||
(US.To_Unbounded_String ("flitch"), 4.0, 30, 0.0),
|
||||
(US.To_Unbounded_String ("brawn"), 2.5, 56, 0.0),
|
||||
(US.To_Unbounded_String ("welt"), 3.7, 67, 0.0),
|
||||
(US.To_Unbounded_String ("salami"), 3.0, 95, 0.0),
|
||||
(US.To_Unbounded_String ("sausage"), 5.9, 98, 0.0));
|
||||
|
||||
begin
|
||||
Solve_Knapsack_Continuous (All_Items, 15.0);
|
||||
Ada.Text_IO.Put_Line
|
||||
("Total Weight: " & Float'Image (Total_Weight (All_Items)));
|
||||
Ada.Text_IO.Put_Line
|
||||
("Total Value: " & Float'Image (Total_Value (All_Items)));
|
||||
Ada.Text_IO.Put_Line ("Items:");
|
||||
for I in All_Items'Range loop
|
||||
if All_Items (I).Taken > 0.0 then
|
||||
Ada.Text_IO.Put_Line
|
||||
(" " &
|
||||
Float'Image (All_Items (I).Taken) &
|
||||
" of " &
|
||||
US.To_String (All_Items (I).Name));
|
||||
end if;
|
||||
end loop;
|
||||
end Knapsack_Continuous;
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
INSTALL @lib$+"SORTSALIB"
|
||||
Sort% = FN_sortSAinit(1, 0) : REM Descending
|
||||
|
||||
nItems% = 9
|
||||
maxWeight = 15.0
|
||||
|
||||
DIM items{(nItems%-1) name$, weight, price, worth}
|
||||
FOR item% = 0 TO nItems%-1
|
||||
READ items{(item%)}.name$, items{(item%)}.weight, items{(item%)}.price
|
||||
items{(item%)}.worth = items{(item%)}.price / items{(item%)}.weight
|
||||
NEXT
|
||||
|
||||
DATA "beef", 3.8, 36, "pork", 5.4, 43, "ham", 3.6, 90
|
||||
DATA "greaves", 2.4, 45, "flitch", 4.0, 30, "brawn", 2.5, 56
|
||||
DATA "welt", 3.7, 67, "salami", 3.0, 95, "sausage", 5.9, 98
|
||||
|
||||
C% = nItems% : D% = 0
|
||||
CALL Sort%, items{()}, items{(0)}.worth
|
||||
|
||||
TotalWeight = 0
|
||||
TotalPrice = 0
|
||||
FOR i% = 0 TO nItems%-1
|
||||
IF TotalWeight + items{(i%)}.weight < maxWeight THEN
|
||||
TotalWeight += items{(i%)}.weight
|
||||
TotalPrice += items{(i%)}.price
|
||||
PRINT "Take all the " items{(i%)}.name$
|
||||
ELSE
|
||||
weight = maxWeight - TotalWeight
|
||||
price = weight * items{(i%)}.worth
|
||||
TotalWeight += weight
|
||||
TotalPrice += price
|
||||
PRINT "Take "; weight " kg of " items{(i%)}.name$
|
||||
EXIT FOR
|
||||
ENDIF
|
||||
NEXT
|
||||
|
||||
PRINT '"Total weight = " ; TotalWeight " kg"
|
||||
PRINT "Total price = " ; TotalPrice
|
||||
END
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#include<iostream>
|
||||
#include<algorithm>
|
||||
#include<string.h>
|
||||
|
||||
using namespace std;
|
||||
double result;
|
||||
double capacity = 15;
|
||||
int NumberOfItems;
|
||||
int number;
|
||||
|
||||
struct items
|
||||
{
|
||||
char name[32];
|
||||
double weight;
|
||||
double price;
|
||||
double m;
|
||||
} item[256];
|
||||
|
||||
bool cmp(items a,items b)
|
||||
{
|
||||
return a.price/a.weight > b.price/b.weight; // the compare function for the sorting algorithm
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
NumberOfItems=9;
|
||||
strcpy(item[1].name,"beef");
|
||||
item[1].weight=3.8;
|
||||
item[1].price=36;
|
||||
|
||||
strcpy(item[2].name,"pork");
|
||||
item[2].weight=5.4;
|
||||
item[2].price=43;
|
||||
|
||||
strcpy(item[3].name,"ham");
|
||||
item[3].weight=3.6;
|
||||
item[3].price=90;
|
||||
|
||||
strcpy(item[4].name,"greaves");
|
||||
item[4].weight=2.4;
|
||||
item[4].price=45;
|
||||
|
||||
strcpy(item[5].name,"flitch");
|
||||
item[5].weight=4.0;
|
||||
item[5].price=30;
|
||||
|
||||
strcpy(item[6].name,"brawn");
|
||||
item[6].weight=2.5;
|
||||
item[6].price=56;
|
||||
|
||||
strcpy(item[7].name,"welt");
|
||||
item[7].weight=3.7;
|
||||
item[7].price=67;
|
||||
|
||||
strcpy(item[8].name,"salami");
|
||||
item[8].weight=3.0;
|
||||
item[8].price=95;
|
||||
|
||||
strcpy(item[9].name,"sausage");
|
||||
item[9].weight=5.9;
|
||||
item[9].price=98;
|
||||
|
||||
|
||||
sort(item+1,item+NumberOfItems+1,cmp); // We'll sort using Introsort from STL
|
||||
|
||||
number = 1;
|
||||
while(capacity>0&&number<=NumberOfItems)
|
||||
{
|
||||
if(item[number].weight<=capacity)
|
||||
{
|
||||
result+=item[number].price;
|
||||
capacity-=item[number].weight;
|
||||
item[number].m=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result+=(item[number].price)*(capacity/item[number].weight);
|
||||
item[number].m=(capacity/item[number].weight);
|
||||
capacity=0;
|
||||
|
||||
}
|
||||
++number;
|
||||
}
|
||||
|
||||
cout<<"Total Value = "<<result<<'\n';
|
||||
cout<<"Total Weight = "<<(double)15-capacity<<'\n';
|
||||
cout<<"Items Used:\n";
|
||||
for(int i=1;i<=NumberOfItems;++i)
|
||||
if(item[i].m)
|
||||
{
|
||||
cout<<"We took "<<item[i].m*item[i].weight<<"kg of \""<<item[i].name<<"\" and the value it brought is "<<item[i].price*item[i].m<<"\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct item { double w, v; const char *name; } items[] = {
|
||||
{ 3.8, 36, "beef" },
|
||||
{ 5.4, 43, "pork" },
|
||||
{ 3.6, 90, "ham" },
|
||||
{ 2.4, 45, "greaves" },
|
||||
{ 4.0, 30, "flitch" },
|
||||
{ 2.5, 56, "brawn" },
|
||||
{ 3.7, 67, "welt" },
|
||||
{ 3.0, 95, "salami" },
|
||||
{ 5.9, 98, "sausage" },
|
||||
};
|
||||
|
||||
int item_cmp(const void *aa, const void *bb)
|
||||
{
|
||||
const struct item *a = aa, *b = bb;
|
||||
double ua = a->v / a->w, ub = b->v / b->w;
|
||||
return ua < ub ? -1 : ua > ub;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct item *it;
|
||||
double space = 15;
|
||||
|
||||
qsort(items, 9, sizeof(struct item), item_cmp);
|
||||
for (it = items + 9; it---items && space > 0; space -= it->w)
|
||||
if (space >= it->w)
|
||||
printf("take all %s\n", it->name);
|
||||
else
|
||||
printf("take %gkg of %g kg of %s\n",
|
||||
space, it->w, it->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import std.stdio, std.algorithm, std.string, std.conv;
|
||||
|
||||
struct Item {
|
||||
string name;
|
||||
real amount, value;
|
||||
|
||||
@property real valuePerKG() const pure nothrow {
|
||||
return value / amount;
|
||||
}
|
||||
|
||||
string toString() const /*pure nothrow*/ {
|
||||
return format("%10s %7.2f %7.2f %7.2f",
|
||||
name, amount, value, valuePerKG);
|
||||
}
|
||||
}
|
||||
|
||||
real sum(string field)(in Item[] items) pure nothrow {
|
||||
return reduce!("a + b." ~ field)(0.0L, items);
|
||||
}
|
||||
|
||||
void main() {
|
||||
Item[] raw = [{"beef", 3.8, 36.0},
|
||||
{"pork", 5.4, 43.0},
|
||||
{"ham", 3.6, 90.0},
|
||||
{"greaves", 2.4, 45.0},
|
||||
{"flitch", 4.0, 30.0},
|
||||
{"brawn", 2.5, 56.0},
|
||||
{"welt", 3.7, 67.0},
|
||||
{"salami", 3.0, 95.0},
|
||||
{"sausage", 5.9, 98.0}];
|
||||
|
||||
// reverse sorted by Value per amount
|
||||
const items = raw.sort!q{a.valuePerKG > b.valuePerKG}().release();
|
||||
|
||||
const(Item)[] chosen;
|
||||
real space = 15.0;
|
||||
foreach (item; items)
|
||||
if (item.amount < space) {
|
||||
chosen ~= item;
|
||||
space -= item.amount;
|
||||
} else {
|
||||
chosen ~= Item(item.name, space, item.valuePerKG * space);
|
||||
break;
|
||||
}
|
||||
|
||||
writefln("%10s %7s %7s %7s", "ITEM", "AMOUNT", "VALUE", "$/unit");
|
||||
writefln("%(%s\n%)", chosen);
|
||||
writeln(Item("TOTAL", sum!"amount"(chosen), sum!"value"(chosen)));
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import std.stdio, std.algorithm;
|
||||
|
||||
void main() {
|
||||
static struct T { string item; double weight, price; }
|
||||
auto items = [T("beef", 3.8, 36.0),
|
||||
T("pork", 5.4, 43.0),
|
||||
T("ham", 3.6, 90.0),
|
||||
T("greaves", 2.4, 45.0),
|
||||
T("flitch", 4.0, 30.0),
|
||||
T("brawn", 2.5, 56.0),
|
||||
T("welt", 3.7, 67.0),
|
||||
T("salami", 3.0, 95.0),
|
||||
T("sausage", 5.9, 98.0)];
|
||||
sort!q{a.price/a.weight > b.price/b.weight}(items);
|
||||
|
||||
auto left = 15.0;
|
||||
foreach (it; items) {
|
||||
if (it.weight <= left) {
|
||||
writeln("Take all the ", it.item);
|
||||
if (it.weight == left)
|
||||
return;
|
||||
left -= it.weight;
|
||||
} else {
|
||||
writefln("Take %.1fkg %s", left, it.item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
include lib/selcsort.4th \ use a tiny sorting algorithm
|
||||
|
||||
150 value left \ capacity in 1/10th kilo
|
||||
|
||||
create items \ list of items
|
||||
," beef" 38 , 3600 , \ description, weight, price (cents)
|
||||
," pork" 54 , 4300 , \ weight in 1/10 kilo
|
||||
," ham" 36 , 9000 ,
|
||||
," greaves" 24 , 4500 ,
|
||||
," flitch" 40 , 3000 ,
|
||||
," brawn" 25 , 5600 ,
|
||||
," welt" 37 , 6700 ,
|
||||
," salami" 30 , 9500 ,
|
||||
," sausage" 59 , 9800 ,
|
||||
here items - 3 / constant #items \ total number of items
|
||||
|
||||
:redo items swap 3 cells * + ; \ calculate address of record
|
||||
|
||||
#items array (items) \ array for sorting
|
||||
( a -- n)
|
||||
: price/weight dup 2 cells + @c swap cell+ @c / ;
|
||||
: weight@ @ cell+ @c ; ( a -- n)
|
||||
: .item @ @c count type cr ; ( a --)
|
||||
\ how to sort: on price/weight
|
||||
:noname >r price/weight r> price/weight > ; is precedes
|
||||
|
||||
: knapsack ( --)
|
||||
(items) dup #items dup 0 ?do i items (items) i th ! loop sort
|
||||
begin \ use the sorted array
|
||||
dup weight@ left <= \ still room in the knapsack?
|
||||
while
|
||||
." Take all of the " dup .item \ take all of the item
|
||||
left over weight@ - to left cell+ \ adjust knapsack, increment item
|
||||
repeat left 100 * dup \ so how much is left?
|
||||
\ if room, take as much as possible
|
||||
if ." Take " . ." grams of the " .item else drop drop then
|
||||
;
|
||||
|
||||
knapsack
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
program KNAPSACK_CONTINUOUS
|
||||
implicit none
|
||||
|
||||
real, parameter :: maxweight = 15.0
|
||||
real :: total_weight = 0, total_value = 0, frac
|
||||
integer :: i, j
|
||||
|
||||
type Item
|
||||
character(7) :: name
|
||||
real :: weight
|
||||
real :: value
|
||||
end type Item
|
||||
|
||||
type(Item) :: items(9), temp
|
||||
|
||||
items(1) = Item("beef", 3.8, 36.0)
|
||||
items(2) = Item("pork", 5.4, 43.0)
|
||||
items(3) = Item("ham", 3.6, 90.0)
|
||||
items(4) = Item("greaves", 2.4, 45.0)
|
||||
items(5) = Item("flitch", 4.0, 30.0)
|
||||
items(6) = Item("brawn", 2.5, 56.0)
|
||||
items(7) = Item("welt", 3.7, 67.0)
|
||||
items(8) = Item("salami", 3.0, 95.0)
|
||||
items(9) = Item("sausage", 5.9, 98.0)
|
||||
|
||||
! sort items in desending order of their value per unit weight
|
||||
do i = 2, size(items)
|
||||
j = i - 1
|
||||
temp = items(i)
|
||||
do while (j>=1 .and. items(j)%value / items(j)%weight < temp%value / temp%weight)
|
||||
items(j+1) = items(j)
|
||||
j = j - 1
|
||||
end do
|
||||
items(j+1) = temp
|
||||
end do
|
||||
|
||||
i = 0
|
||||
write(*, "(a4, a13, a6)") "Item", "Weight", "Value"
|
||||
do while(i < size(items) .and. total_weight < maxweight)
|
||||
i = i + 1
|
||||
if(total_weight+items(i)%weight < maxweight) then
|
||||
total_weight = total_weight + items(i)%weight
|
||||
total_value = total_value + items(i)%value
|
||||
write(*, "(a7, 2f8.2)") items(i)
|
||||
else
|
||||
frac = (maxweight-total_weight) / items(i)%weight
|
||||
total_weight = total_weight + items(i)%weight * frac
|
||||
total_value = total_value + items(i)%value * frac
|
||||
write(*, "(a7, 2f8.2)") items(i)%name, items(i)%weight * frac, items(i)%value * frac
|
||||
end if
|
||||
end do
|
||||
|
||||
write(*, "(f15.2, f8.2)") total_weight, total_value
|
||||
|
||||
end program KNAPSACK_CONTINUOUS
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type item struct {
|
||||
item string
|
||||
weight float64
|
||||
price float64
|
||||
}
|
||||
|
||||
type items []item
|
||||
|
||||
var all = items{
|
||||
{"beef", 3.8, 36},
|
||||
{"pork", 5.4, 43},
|
||||
{"ham", 3.6, 90},
|
||||
{"greaves", 2.4, 45},
|
||||
{"flitch", 4.0, 30},
|
||||
{"brawn", 2.5, 56},
|
||||
{"welt", 3.7, 67},
|
||||
{"salami", 3.0, 95},
|
||||
{"sausage", 5.9, 98},
|
||||
}
|
||||
|
||||
// satisfy sort interface
|
||||
func (z items) Len() int { return len(z) }
|
||||
func (z items) Swap(i, j int) { z[i], z[j] = z[j], z[i] }
|
||||
func (z items) Less(i, j int) bool {
|
||||
return z[i].price/z[i].weight > z[j].price/z[j].weight
|
||||
}
|
||||
|
||||
func main() {
|
||||
left := 15.
|
||||
sort.Sort(all)
|
||||
for _, i := range all {
|
||||
if i.weight <= left {
|
||||
fmt.Println("take all the", i.item)
|
||||
if i.weight == left {
|
||||
return
|
||||
}
|
||||
left -= i.weight
|
||||
} else {
|
||||
fmt.Printf("take %.1fkg %s\n", left, i.item)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import static java.math.RoundingMode.*
|
||||
|
||||
def knapsackCont = { list, maxWeight = 15.0 ->
|
||||
list.sort{ it.weight / it.value }
|
||||
def remainder = maxWeight
|
||||
List sack = []
|
||||
for (item in list) {
|
||||
if (item.weight < remainder) {
|
||||
sack << [name: item.name, weight: item.weight,
|
||||
value: (item.value as BigDecimal).setScale(2, HALF_UP)]
|
||||
} else {
|
||||
sack << [name: item.name, weight: remainder,
|
||||
value: (item.value * remainder / item.weight).setScale(2, HALF_UP)]
|
||||
break
|
||||
}
|
||||
remainder -= item.weight
|
||||
}
|
||||
sack
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
def possibleItems = [
|
||||
[name:'beef', weight:3.8, value:36],
|
||||
[name:'pork', weight:5.4, value:43],
|
||||
[name:'ham', weight:3.6, value:90],
|
||||
[name:'greaves', weight:2.4, value:45],
|
||||
[name:'flitch', weight:4.0, value:30],
|
||||
[name:'brawn', weight:2.5, value:56],
|
||||
[name:'welt', weight:3.7, value:67],
|
||||
[name:'salami', weight:3.0, value:95],
|
||||
[name:'sausage', weight:5.9, value:98],
|
||||
]
|
||||
|
||||
def contents = knapsackCont(possibleItems)
|
||||
println "Total Value: ${contents*.value.sum()}"
|
||||
contents.each {
|
||||
printf(" name: %-7s weight: ${it.weight} value: ${it.value}\n", it.name)
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import Control.Monad
|
||||
import Data.List (sortBy)
|
||||
import Data.Ord (comparing)
|
||||
import Data.Ratio (numerator, denominator)
|
||||
import Text.Printf
|
||||
|
||||
maxWgt = 15
|
||||
|
||||
data Bounty = Bounty
|
||||
{itemName :: String,
|
||||
itemVal, itemWgt :: Rational}
|
||||
|
||||
items =
|
||||
[Bounty "beef" 36 3.8,
|
||||
Bounty "pork" 43 5.4,
|
||||
Bounty "ham" 90 3.6,
|
||||
Bounty "greaves" 45 2.4,
|
||||
Bounty "flitch" 30 4.0,
|
||||
Bounty "brawn" 56 2.5,
|
||||
Bounty "welt" 67 3.7,
|
||||
Bounty "salami" 95 3.0,
|
||||
Bounty "sausage" 98 5.9]
|
||||
|
||||
solution :: [(Rational, Bounty)]
|
||||
solution = g maxWgt $ sortBy (flip $ comparing f) items
|
||||
where g room (b@(Bounty _ _ w) : bs) = if w < room
|
||||
then (w, b) : g (room - w) bs
|
||||
else [(room, b)]
|
||||
f (Bounty _ v w) = v / w
|
||||
|
||||
main = do
|
||||
forM_ solution $ \(w, b) ->
|
||||
printf "%s kg of %s\n" (mixedNum w) (itemName b)
|
||||
printf "Total value: %s\n" $ mixedNum $ sum $ map f solution
|
||||
where f (w, Bounty _ v wtot) = v * (w / wtot)
|
||||
mixedNum q = if b == 0
|
||||
then show a
|
||||
else printf "%d %d/%d" a (numerator b) (denominator b)
|
||||
where a = floor q
|
||||
b = q - toEnum a
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import Data.List (sortBy)
|
||||
import Data.Ord (comparing)
|
||||
import Text.Printf (printf)
|
||||
|
||||
-- (name, (value, weight))
|
||||
items = [("beef", (36, 3.8)),
|
||||
("pork", (43, 5.4)),
|
||||
("ham", (90, 3.6)),
|
||||
("greaves", (45, 2.4)),
|
||||
("flitch", (30, 4.0)),
|
||||
("brawn", (56, 2.5)),
|
||||
("welt", (67, 3.7)),
|
||||
("salami", (95, 3.0)),
|
||||
("sausage", (98, 5.9))]
|
||||
|
||||
unitWeight (_, (val, weight)) = (fromIntegral val) / weight
|
||||
|
||||
solution k = loop k . sortBy (flip $ comparing unitWeight)
|
||||
where loop k ((name, (_, weight)):xs)
|
||||
| weight < k = putStrLn ("Take all the " ++ name) >> loop (k-weight) xs
|
||||
| otherwise = printf "Take %.2f kg of the %s\n" (k :: Float) name
|
||||
|
||||
main = solution 15 items
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
link printf
|
||||
|
||||
procedure main()
|
||||
room := 15
|
||||
every (x := !(choices := get_items())).uprice := x.price / x.weight
|
||||
choices := reverse(sortf(choices,4))
|
||||
|
||||
every (value := 0, x := !choices) do {
|
||||
if x.weight <= room then {
|
||||
printf("Take all of the %s (%r kg) worth $%r\n",x.name,x.weight,x.price)
|
||||
value +:= x.price
|
||||
room -:= x.weight
|
||||
}
|
||||
else {
|
||||
fvalue := x.uprice * room
|
||||
printf("Take (%r kg) of the %s worth $%r\n",room,x.name,fvalue)
|
||||
value +:= fvalue
|
||||
break
|
||||
}
|
||||
}
|
||||
printf("Total value of a full knapsack is $%r\n",value)
|
||||
end
|
||||
|
||||
record item(name,weight,price,uprice)
|
||||
|
||||
procedure get_items()
|
||||
return [ item("beef", 3.8, 36),
|
||||
item("pork", 5.4, 43),
|
||||
item("ham", 3.6, 90),
|
||||
item("greaves", 2.4, 45),
|
||||
item("flitch", 4.0, 30),
|
||||
item("brawn", 2.5, 56),
|
||||
item("welt", 3.7, 67),
|
||||
item("salami", 3.0, 95),
|
||||
item("sausage", 5.9, 98) ]
|
||||
end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
'names numbers'=:|:;:;._2]0 :0
|
||||
beef 3.8 36
|
||||
pork 5.4 43
|
||||
ham 3.6 90
|
||||
greaves 2.4 45
|
||||
flitch 4.0 30
|
||||
brawn 2.5 56
|
||||
welt 3.7 67
|
||||
salami 3.0 95
|
||||
sausage 5.9 98
|
||||
)
|
||||
'weights prices'=:|:".numbers
|
||||
order=: \:prices%weights
|
||||
take=: 15&<.&.(+/\) order{weights
|
||||
result=: (*take)#(order{names),.' ',.":,.take
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
+/prices * (take/:order) % weights
|
||||
349.378
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package hu.pj.alg.test;
|
||||
|
||||
import hu.pj.alg.ContinuousKnapsack;
|
||||
import hu.pj.obj.Item;
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
|
||||
public class ContinousKnapsackForRobber {
|
||||
final private double tolerance = 0.0005;
|
||||
|
||||
public ContinousKnapsackForRobber() {
|
||||
ContinuousKnapsack cok = new ContinuousKnapsack(15); // 15 kg
|
||||
|
||||
// making the list of items that you want to bring
|
||||
cok.add("beef", 3.8, 36); // marhahús
|
||||
cok.add("pork", 5.4, 43); // disznóhús
|
||||
cok.add("ham", 3.6, 90); // sonka
|
||||
cok.add("greaves", 2.4, 45); // tepertő
|
||||
cok.add("flitch", 4.0, 30); // oldalas
|
||||
cok.add("brawn", 2.5, 56); // disznósajt
|
||||
cok.add("welt", 3.7, 67); // hurka
|
||||
cok.add("salami", 3.0, 95); // szalámi
|
||||
cok.add("sausage", 5.9, 98); // kolbász
|
||||
|
||||
// calculate the solution:
|
||||
List<Item> itemList = cok.calcSolution();
|
||||
|
||||
// write out the solution in the standard output
|
||||
if (cok.isCalculated()) {
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
|
||||
System.out.println(
|
||||
"Maximal weight = " +
|
||||
nf.format(cok.getMaxWeight()) + " kg"
|
||||
);
|
||||
System.out.println(
|
||||
"Total weight of solution = " +
|
||||
nf.format(cok.getSolutionWeight()) + " kg"
|
||||
);
|
||||
System.out.println(
|
||||
"Total value (profit) = " +
|
||||
nf.format(cok.getProfit())
|
||||
);
|
||||
System.out.println();
|
||||
System.out.println(
|
||||
"You can carry the following materials " +
|
||||
"in the knapsack:"
|
||||
);
|
||||
for (Item item : itemList) {
|
||||
if (item.getInKnapsack() > tolerance) {
|
||||
System.out.format(
|
||||
"%1$-10s %2$-15s %3$-15s \n",
|
||||
nf.format(item.getInKnapsack()) + " kg ",
|
||||
item.getName(),
|
||||
"(value = " + nf.format(item.getInKnapsack() *
|
||||
(item.getValue() / item.getWeight())) + ")"
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println(
|
||||
"The problem is not solved. " +
|
||||
"Maybe you gave wrong data."
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new ContinousKnapsackForRobber();
|
||||
}
|
||||
|
||||
} // class
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package hu.pj.alg;
|
||||
|
||||
import hu.pj.obj.Item;
|
||||
import java.util.*;
|
||||
|
||||
public class ContinuousKnapsack {
|
||||
|
||||
protected List<Item> itemList = new ArrayList<Item>();
|
||||
protected double maxWeight = 0;
|
||||
protected double solutionWeight = 0;
|
||||
protected double profit = 0;
|
||||
protected boolean calculated = false;
|
||||
|
||||
public ContinuousKnapsack() {}
|
||||
|
||||
public ContinuousKnapsack(double _maxWeight) {
|
||||
setMaxWeight(_maxWeight);
|
||||
}
|
||||
|
||||
public List<Item> calcSolution() {
|
||||
int n = itemList.size();
|
||||
|
||||
setInitialStateForCalculation();
|
||||
if (n > 0 && maxWeight > 0) {
|
||||
Collections.sort(itemList);
|
||||
for (int i = 0; (maxWeight - solutionWeight) > 0.0 && i < n; i++) {
|
||||
Item item = itemList.get(i);
|
||||
if (item.getWeight() >= (maxWeight - solutionWeight)) {
|
||||
item.setInKnapsack(maxWeight - solutionWeight);
|
||||
solutionWeight = maxWeight;
|
||||
profit += item.getInKnapsack() / item.getWeight() * item.getValue();
|
||||
break;
|
||||
} else {
|
||||
item.setInKnapsack(item.getWeight());
|
||||
solutionWeight += item.getInKnapsack();
|
||||
profit += item.getValue();
|
||||
}
|
||||
}
|
||||
calculated = true;
|
||||
}
|
||||
|
||||
return itemList;
|
||||
}
|
||||
|
||||
// add an item to the item list
|
||||
public void add(String name, double weight, double value) {
|
||||
if (name.equals(""))
|
||||
name = "" + (itemList.size() + 1);
|
||||
itemList.add(new Item(name, weight, value));
|
||||
setInitialStateForCalculation();
|
||||
}
|
||||
|
||||
public double getMaxWeight() {return maxWeight;}
|
||||
public double getProfit() {return profit;}
|
||||
public double getSolutionWeight() {return solutionWeight;}
|
||||
public boolean isCalculated() {return calculated;}
|
||||
|
||||
public void setMaxWeight(double _maxWeight) {
|
||||
maxWeight = Math.max(_maxWeight, 0);
|
||||
}
|
||||
|
||||
// set the member with name "inKnapsack" by all items:
|
||||
private void setInKnapsackByAll(double inKnapsack) {
|
||||
for (Item item : itemList)
|
||||
item.setInKnapsack(inKnapsack);
|
||||
}
|
||||
|
||||
// set the data members of class in the state of starting the calculation:
|
||||
protected void setInitialStateForCalculation() {
|
||||
setInKnapsackByAll(-0.0001);
|
||||
calculated = false;
|
||||
profit = 0.0;
|
||||
solutionWeight = 0.0;
|
||||
}
|
||||
|
||||
} // class
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package hu.pj.obj;
|
||||
|
||||
public class Item implements Comparable {
|
||||
|
||||
protected String name = "";
|
||||
protected double weight = 0;
|
||||
protected double value = 0;
|
||||
protected double inKnapsack = 0; // the weight of item in solution
|
||||
|
||||
public Item() {}
|
||||
|
||||
public Item(Item item) {
|
||||
setName(item.name);
|
||||
setWeight(item.weight);
|
||||
setValue(item.value);
|
||||
}
|
||||
|
||||
public Item(double _weight, double _value) {
|
||||
setWeight(_weight);
|
||||
setValue(_value);
|
||||
}
|
||||
|
||||
public Item(String _name, double _weight, double _value) {
|
||||
setName(_name);
|
||||
setWeight(_weight);
|
||||
setValue(_value);
|
||||
}
|
||||
|
||||
public void setName(String _name) {name = _name;}
|
||||
public void setWeight(double _weight) {weight = Math.max(_weight, 0);}
|
||||
public void setValue(double _value) {value = Math.max(_value, 0);}
|
||||
|
||||
public void setInKnapsack(double _inKnapsack) {
|
||||
inKnapsack = Math.max(_inKnapsack, 0);
|
||||
}
|
||||
|
||||
public void checkMembers() {
|
||||
setWeight(weight);
|
||||
setValue(value);
|
||||
setInKnapsack(inKnapsack);
|
||||
}
|
||||
|
||||
public String getName() {return name;}
|
||||
public double getWeight() {return weight;}
|
||||
public double getValue() {return value;}
|
||||
public double getInKnapsack() {return inKnapsack;}
|
||||
|
||||
// implementing of Comparable interface:
|
||||
public int compareTo(Object item) {
|
||||
int result = 0;
|
||||
Item i2 = (Item)item;
|
||||
double rate1 = value / weight;
|
||||
double rate2 = i2.value / i2.weight;
|
||||
if (rate1 > rate2) result = -1; // if greater, put it previously
|
||||
else if (rate1 < rate2) result = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // class
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
Knapsack[shop_, capacity_] := Block[{sortedTable, overN, overW, output},
|
||||
sortedTable = SortBy[{#1, #2, #3, #3/#2} & @@@ shop, -#[[4]] &];
|
||||
overN = Position[Accumulate[sortedTable[[1 ;;, 2]]], a_ /; a > capacity, 1,1][[1, 1]];
|
||||
overW = Accumulate[sortedTable[[1 ;;, 2]]][[overN]] - capacity;
|
||||
|
||||
output = Reverse@sortedTable[[Ordering[sortedTable[[1 ;;, 4]], -overN]]];
|
||||
output[[-1, 2]] = output[[-1, 2]] - overW;
|
||||
output[[-1, 3]] = output[[-1, 2]] output[[-1, 4]];
|
||||
Append[output[[1 ;;, 1 ;; 3]], {"Total",Sequence @@ Total[output[[1 ;;, 2 ;; 3]]]}]]
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
weightPriceTable =
|
||||
{{"beef", 3.8, 36}, {"pork", 5.4, 43}, {"ham", 3.6, 90}, {"greaves", 2.4, 45}, {"flitch", 4., 30},
|
||||
{"brawn", 2.5, 56}, {"welt", 3.7, 67}, {"salami", 3., 95}, {"sausage", 5.9, 98}};
|
||||
carryCapacity = 15;
|
||||
Knapsack[weightPriceTable, carryCapacity] // Grid
|
||||
|
||||
salami 3. 95
|
||||
ham 3.6 90
|
||||
brawn 2.5 56
|
||||
greaves 2.4 45
|
||||
welt 3.5 63.3784
|
||||
Total 15. 349.378
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*Knapsack
|
||||
|
||||
This model finds the optimal packing of a knapsack
|
||||
|
||||
Nigel_Galloway
|
||||
January 10th., 2012
|
||||
*/
|
||||
set Items;
|
||||
param weight{t in Items};
|
||||
param value{t in Items};
|
||||
|
||||
var take{t in Items}, >=0, <=weight[t];
|
||||
|
||||
knap_weight : sum{t in Items} take[t] <= 15;
|
||||
|
||||
maximize knap_value: sum{t in Items} take[t] * (value[t]/weight[t]);
|
||||
|
||||
data;
|
||||
|
||||
param : Items : weight value :=
|
||||
beef 3.8 36
|
||||
pork 5.4 43
|
||||
ham 3.6 90
|
||||
greaves 2.4 45
|
||||
flitch 4.0 30
|
||||
brawn 2.5 56
|
||||
welt 3.7 67
|
||||
salami 3.0 95
|
||||
sausage 5.9 98
|
||||
;
|
||||
end;
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
my @items = sort { $b->[2]/$b->[1] <=> $a->[2]/$a->[1] }
|
||||
(
|
||||
[qw'beef 3.8 36'],
|
||||
[qw'pork 5.4 43'],
|
||||
[qw'ham 3.6 90'],
|
||||
[qw'greaves 2.4 45'],
|
||||
[qw'flitch 4.0 30'],
|
||||
[qw'brawn 2.5 56'],
|
||||
[qw'welt 3.7 67'],
|
||||
[qw'salami 3.0 95'],
|
||||
[qw'sausage 5.9 98'],
|
||||
);
|
||||
|
||||
my ($limit, $value) = (15, 0);
|
||||
|
||||
print "item fraction weight value\n";
|
||||
for (@items) {
|
||||
my $ratio = $_->[1] > $limit ? $limit/$_->[1] : 1;
|
||||
print "$_->[0]\t";
|
||||
$value += $_->[2] * $ratio;
|
||||
$limit -= $_->[1];
|
||||
if ($ratio == 1) {
|
||||
print " all\t$_->[1]\t$_->[2]\n";
|
||||
} else {
|
||||
printf "%5.3f %s %8.3f\n", $ratio, $_->[1] * $ratio, $_->[2] * $ratio;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
print "-" x 40, "\ntotal value: $value\n";
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
(scl 2)
|
||||
|
||||
(de *Items
|
||||
("beef" 3.8 36.0)
|
||||
("pork" 5.4 43.0)
|
||||
("ham" 3.6 90.0)
|
||||
("greaves" 2.4 45.0)
|
||||
("flitch" 4.0 30.0)
|
||||
("brawn" 2.5 56.0)
|
||||
("welt" 3.7 67.0)
|
||||
("salami" 3.0 95.0)
|
||||
("sausage" 5.9 98.0) )
|
||||
|
||||
(let K
|
||||
(make
|
||||
(let Weight 0
|
||||
(for I (by '((L) (*/ (caddr L) -1.0 (cadr L))) sort *Items)
|
||||
(T (= Weight 15.0))
|
||||
(inc 'Weight (cadr I))
|
||||
(T (> Weight 15.0)
|
||||
(let W (- (cadr I) Weight -15.0)
|
||||
(link (list (car I) W (*/ W (caddr I) (cadr I)))) ) )
|
||||
(link I) ) ) )
|
||||
(for I K
|
||||
(tab (3 -9 8 8)
|
||||
NIL
|
||||
(car I)
|
||||
(format (cadr I) *Scl)
|
||||
(format (caddr I) *Scl) ) )
|
||||
(tab (12 8 8)
|
||||
NIL
|
||||
(format (sum cadr K) *Scl)
|
||||
(format (sum caddr K) *Scl) ) )
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
:- use_module(library(simplex)).
|
||||
% tuples (name, weights, value).
|
||||
knapsack :-
|
||||
L = [( beef, 3.8, 36),
|
||||
( pork, 5.4, 43),
|
||||
( ham, 3.6, 90),
|
||||
( greaves, 2.4, 45),
|
||||
( flitch, 4.0, 30),
|
||||
( brawn, 2.5, 56),
|
||||
( welt, 3.7, 67),
|
||||
( salami, 3.0, 95),
|
||||
( sausage, 5.9, 98)],
|
||||
|
||||
gen_state(S0),
|
||||
length(L, N),
|
||||
numlist(1, N, LN),
|
||||
( ( create_constraint_N(LN, L, S0, S1, [], LW, [], LV),
|
||||
constraint(LW =< 15.0, S1, S2),
|
||||
maximize(LV, S2, S3)
|
||||
)),
|
||||
compute_lenword(L, 0, Len),
|
||||
sformat(A1, '~~w~~t~~~w|', [Len]),
|
||||
sformat(A2, '~~t~~2f~~~w|', [10]),
|
||||
sformat(A3, '~~t~~2f~~~w|', [10]),
|
||||
print_results(S3, A1,A2,A3, L, LN, 0, 0).
|
||||
|
||||
|
||||
create_constraint_N([], [], S, S, LW, LW, LV, LV).
|
||||
|
||||
create_constraint_N([HN|TN], [(_, W, V) | TL], S1, SF, LW, LWF, LV, LVF) :-
|
||||
constraint([x(HN)] >= 0, S1, S2),
|
||||
constraint([x(HN)] =< W, S2, S3),
|
||||
X is V/W,
|
||||
create_constraint_N(TN, TL, S3, SF, [x(HN) | LW], LWF, [X * x(HN) | LV], LVF).
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%
|
||||
compute_lenword([], N, N).
|
||||
compute_lenword([(Name, _, _)|T], N, NF):-
|
||||
atom_length(Name, L),
|
||||
( L > N -> N1 = L; N1 = N),
|
||||
compute_lenword(T, N1, NF).
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%
|
||||
print_results(_S, A1, A2, A3, [], [], WM, VM) :-
|
||||
sformat(W1, A1, [' ']),
|
||||
sformat(W2, A2, [WM]),
|
||||
sformat(W3, A3, [VM]),
|
||||
format('~w~w~w~n', [W1,W2,W3]).
|
||||
|
||||
|
||||
print_results(S, A1, A2, A3, [(Name, W, V)|T], [N|TN], W1, V1) :-
|
||||
variable_value(S, x(N), X),
|
||||
( X = 0 -> W1 = W2, V1 = V2
|
||||
;
|
||||
sformat(S1, A1, [Name]),
|
||||
sformat(S2, A2, [X]),
|
||||
Vtemp is X * V/W,
|
||||
sformat(S3, A3, [Vtemp]),
|
||||
format('~w~w~w~n', [S1,S2,S3]),
|
||||
W2 is W1 + X,
|
||||
V2 is V1 + Vtemp ),
|
||||
print_results(S, A1, A2, A3, T, TN, W2, V2).
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# NAME, WEIGHT, VALUE (for this weight)
|
||||
items = [("beef", 3.8, 36.0),
|
||||
("pork", 5.4, 43.0),
|
||||
("ham", 3.6, 90.0),
|
||||
("greaves", 2.4, 45.0),
|
||||
("flitch", 4.0, 30.0),
|
||||
("brawn", 2.5, 56.0),
|
||||
("welt", 3.7, 67.0),
|
||||
("salami", 3.0, 95.0),
|
||||
("sausage", 5.9, 98.0)]
|
||||
|
||||
MAXWT = 15.0
|
||||
|
||||
sorted_items = sorted(((value/amount, amount, name)
|
||||
for name, amount, value in items),
|
||||
reverse = True)
|
||||
wt = val = 0
|
||||
bagged = []
|
||||
for unit_value, amount, name in sorted_items:
|
||||
portion = min(MAXWT - wt, amount)
|
||||
wt += portion
|
||||
addval = portion * unit_value
|
||||
val += addval
|
||||
bagged += [(name, portion, addval)]
|
||||
if wt >= MAXWT:
|
||||
break
|
||||
|
||||
print(" ITEM PORTION VALUE")
|
||||
print("\n".join("%10s %6.2f %6.2f" % item for item in bagged))
|
||||
print("\nTOTAL WEIGHT: %5.2f\nTOTAL VALUE: %5.2f" % (wt, val))
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*REXX program to solve the burglar's knapsack (continuous) problem. */
|
||||
@.=''
|
||||
/*════ name weight value ════*/
|
||||
@.1 = 'flitch 4 30 '
|
||||
@.2 = 'beef 3.8 36 '
|
||||
@.3 = 'pork 5.4 43 '
|
||||
@.4 = 'greaves 2.4 45 '
|
||||
@.5 = 'brawn 2.5 56 '
|
||||
@.6 = 'welt 3.7 67 '
|
||||
@.7 = 'ham 3.6 90 '
|
||||
@.8 = 'salami 3 95 '
|
||||
@.9 = 'sausage 5.9 98 '
|
||||
|
||||
nL=length('total weight'); wL=length('weight'); vL=length(' value ')
|
||||
totW=0; totV=0
|
||||
do j=1 while @.j\=='' ; parse var @.j n w v .
|
||||
nL=max(nL,length(n)) ; n.j=n
|
||||
totW=totW+w ; w.j=w
|
||||
totV=totV+v ; v.j=v
|
||||
end /*j*/
|
||||
items=j-1 /*items is the number of items. */
|
||||
nL=nL+nL%4 /*nL: max length name + 25%. */
|
||||
wL=max(wL,length(format(totw,,2))) /*wL: max formatted weight width*/
|
||||
vL=max(vL,length(format(totv,,2))) /*vL: max formatted value width*/
|
||||
totW=0; totV=0
|
||||
call show 'before sorting'
|
||||
|
||||
do j=2 to items /*sort by desending value/unit wt*/
|
||||
k=j-1; _n=n.j; _w=w.j; _v=v.j
|
||||
do k=k by -1 to 1 while v.k/w.k < _v/_w
|
||||
kp1=k+1; n.kp1=n.k; w.kp1=w.k; v.kp1=v.k
|
||||
end /*k*/
|
||||
kp1=k+1; n.kp1=_n; w.kp1=_w; v.kp1=_v
|
||||
end /*j*/
|
||||
|
||||
call show 'after sorting'
|
||||
call hdr "burgler's knapsack contents"
|
||||
maxW=15 /*burgler's knapsack max weight. */
|
||||
do j=1 for items while totW < maxW
|
||||
if totW+w.j<maxW then do
|
||||
totW=totW + w.j
|
||||
totV=totV + v.j
|
||||
call syf n.j, w.j, v.j
|
||||
end
|
||||
else do
|
||||
f=(maxW-totW) / w.j
|
||||
totW=totW + w.j*f
|
||||
totV=totV + v.j*f
|
||||
call syf n.j, w.j*f, v.j*f
|
||||
end
|
||||
end /*j*/
|
||||
call sep
|
||||
call sy left('total weight',nL,'─'), format(totW,,2)
|
||||
call sy left('total value',nL,'─'), , format(totV,,2)
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────one─liner subroutines───────────────*/
|
||||
hdr: indent=left('',9); call verse arg(1); call title; call sep; return
|
||||
sep: call sy copies('═',nL), copies("═",wL), copies('═',vL); return
|
||||
show: call hdr arg(1); do j=1 for items; call syf n.j,w.j,v.j;end; say; return
|
||||
sy: say indent left(arg(1),nL) right(arg(2),wL) right(arg(3),vL); return
|
||||
syf: call sy arg(1), format(arg(2),,2), format(arg(3),,2); return
|
||||
title: call sy center('item',nL),center("weight",wL),center('value',vL); return
|
||||
verse: say; say center(arg(1),50,'─'); say; return
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package require Tcl 8.5
|
||||
|
||||
# Uses the trivial greedy algorithm
|
||||
proc continuousKnapsack {items massLimit} {
|
||||
# Add in the unit prices
|
||||
set idx -1
|
||||
foreach item $items {
|
||||
lassign $item name mass value
|
||||
lappend item [expr {$value / $mass}]
|
||||
lset items [incr idx] $item
|
||||
}
|
||||
|
||||
# Sort by unit prices
|
||||
set items [lsort -decreasing -real -index 3 $items]
|
||||
|
||||
# Add items, using most valuable-per-unit first
|
||||
set result {}
|
||||
set total 0.0
|
||||
set totalValue 0
|
||||
foreach item $items {
|
||||
lassign $item name mass value unit
|
||||
if {$total + $mass < $massLimit} {
|
||||
lappend result [list $name $mass $value]
|
||||
set total [expr {$total + $mass}]
|
||||
set totalValue [expr {$totalValue + $value}]
|
||||
} else {
|
||||
set mass [expr {$massLimit - $total}]
|
||||
set value [expr {$unit * $mass}]
|
||||
lappend result [list $name $mass $value]
|
||||
set totalValue [expr {$totalValue + $value}]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# We return the total value too, purely for convenience
|
||||
return [list $result $totalValue]
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
set items {
|
||||
{beef 3.8 36}
|
||||
{pork 5.4 43}
|
||||
{ham 3.6 90}
|
||||
{greaves 2.4 45}
|
||||
{flitch 4.0 30}
|
||||
{brawn 2.5 56}
|
||||
{welt 3.7 67}
|
||||
{salami 3.0 95}
|
||||
{sausage 5.9 98}
|
||||
}
|
||||
|
||||
lassign [continuousKnapsack $items 15.0] contents totalValue
|
||||
puts [format "total value of knapsack: %.2f" $totalValue]
|
||||
puts "contents:"
|
||||
foreach item $contents {
|
||||
lassign $item name mass value
|
||||
puts [format "\t%.1fkg of %s, value %.2f" $mass $name $value]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue