104 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			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 |