factor/extra/rosetta-code/knapsack/knapsack.factor

104 lines
3.2 KiB
Factor

! Copyright (c) 2012 Anonymous
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays fry io kernel locals make math
math.order math.parser math.ranges sequences sorting ;
IN: rosetta-code.knapsack
! http://rosettacode.org/wiki/Knapsack_problem/0-1
! 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.
! 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?
TUPLE: item
name weight value ;
CONSTANT: items {
T{ item f "map" 9 150 }
T{ item f "compass" 13 35 }
T{ item f "water" 153 200 }
T{ item f "sandwich" 50 160 }
T{ item f "glucose" 15 60 }
T{ item f "tin" 68 45 }
T{ item f "banana" 27 60 }
T{ item f "apple" 39 40 }
T{ item f "cheese" 23 30 }
T{ item f "beer" 52 10 }
T{ item f "suntan cream" 11 70 }
T{ item f "camera" 32 30 }
T{ item f "t-shirt" 24 15 }
T{ item f "trousers" 48 10 }
T{ item f "umbrella" 73 40 }
T{ item f "waterproof trousers" 42 70 }
T{ item f "waterproof overclothes" 43 75 }
T{ item f "note-case" 22 80 }
T{ item f "sunglasses" 7 20 }
T{ item f "towel" 18 12 }
T{ item f "socks" 4 50 }
T{ item f "book" 30 10 }
}
CONSTANT: limit 400
: make-table ( -- table )
items length 1 + [ limit 1 + 0 <array> ] replicate ;
:: iterate ( item-no table -- )
item-no table nth :> prev
item-no 1 + table nth :> curr
item-no items nth :> item
limit [1,b] [| weight |
weight prev nth
weight item weight>> - dup 0 >=
[ prev nth item value>> + max ]
[ drop ] if
weight curr set-nth
] each ;
: fill-table ( table -- )
[ items length <iota> ] dip
'[ _ iterate ] each ;
:: extract-packed-items ( table -- items )
[
limit :> weight!
items length <iota> <reversed> [| item-no |
item-no table nth :> prev
item-no 1 + table nth :> curr
weight [ curr nth ] [ prev nth ] bi =
[
item-no items nth
[ name>> , ] [ weight>> weight swap - weight! ] bi
] unless
] each
] { } make ;
: solve-knapsack ( -- items value )
make-table [ fill-table ]
[ extract-packed-items ] [ last last ] tri ;
: knapsack-main ( -- )
solve-knapsack
"Total value: " write number>string print
"Items packed: " print
natural-sort
[ " " write print ] each ;
MAIN: knapsack-main