2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,7 +1,13 @@
|
|||
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 some items during the trip. Food, clothing, etc. He has a good knapsack for carrying the things, but he knows that he can carry only 4 kg weight in his knapsack, because they will make the trip from morning to evening. He creates a list of what he wants to bring for the trip, but the total weight of all items is too much. He adds a value to each item. The value represents how important the thing for the tourist. The list contains which items are the wanted things for the trip, what is the weight and value of an item, and how many units does he have from each items.
|
||||
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 some items during the trip. Food, clothing, etc. He has a good knapsack for carrying the things, but he knows that he can carry only 4 kg weight in his knapsack, because they will make the trip from morning to evening.
|
||||
|
||||
He creates a list of what he wants to bring for the trip, but the total weight of all items is too much. He adds a value to each item. The value represents how important the thing for the tourist.
|
||||
|
||||
The list contains which items are the wanted things for the trip, what is the weight and value of an item, and how many units does he have from each items.
|
||||
|
||||
|
||||
This is the list:
|
||||
|
||||
{| style="text-align: left; width: 80%;" border="4" cellpadding="2" cellspacing="2"
|
||||
|+ Table of potential knapsack items
|
||||
|- style="background-color: rgb(255, 204, 255);"
|
||||
|
|
@ -54,8 +60,17 @@ This is the list:
|
|||
| knapsack || ≤400 dag || ? || ?
|
||||
|}
|
||||
|
||||
The tourist can choose to take any combination of items from the list, and some number of each item is available (see the column "Piece(s)" of the list!). He may not cut the items, so he can only take whole units of any item.
|
||||
<br>
|
||||
The tourist can choose to take any combination of items from the list, and some number of each item is available (see the column '''piece(s)''' in the list above).
|
||||
|
||||
'''Which items does the tourist carry in his knapsack so that their total weight does not exceed 4 kg, and their total value is maximised?'''
|
||||
He may not cut the items, so he can only take whole units of any item.
|
||||
|
||||
See also: [[Knapsack problem/Unbounded]], [[Knapsack problem/0-1]]
|
||||
|
||||
;Task:
|
||||
Show which items does the tourist carry in his knapsack so that their total weight does not exceed 4 kg, and their total value is maximized.
|
||||
|
||||
|
||||
;Related tasks:
|
||||
* [[Knapsack problem/Unbounded]]
|
||||
* [[Knapsack problem/0-1]]
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -1,114 +1,84 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define max_weight 400
|
||||
|
||||
typedef struct { const char *name; int w, v, qty; } item_t;
|
||||
typedef struct {
|
||||
char *name;
|
||||
int weight;
|
||||
int value;
|
||||
int count;
|
||||
} item_t;
|
||||
|
||||
item_t items[] = {
|
||||
{"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},
|
||||
{"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-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},
|
||||
{"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},
|
||||
};
|
||||
|
||||
/* for C, the main problem is not the algorithm: it's cache management */
|
||||
#define n_types (sizeof(items)/sizeof(item_t))
|
||||
typedef struct {
|
||||
int v, w; /* value & weight total */
|
||||
unsigned short n[n_types]; /* num of each item taken */
|
||||
} solution_t, *solution;
|
||||
int n = sizeof (items) / sizeof (item_t);
|
||||
|
||||
solution_t *cache, *blank;
|
||||
|
||||
int init_cache()
|
||||
{
|
||||
/* a flat array. If problem size is large, might be a bad idea;
|
||||
* then again, other caching method face similar issue, too
|
||||
*/
|
||||
size_t i;
|
||||
size_t n_rec = (max_weight + 1) * n_types;
|
||||
cache = calloc(sizeof(solution_t), (n_rec + 1));
|
||||
if (!cache) return 0;
|
||||
|
||||
for (i = 0; i <= n_rec; i++) {
|
||||
cache[i].v = -1; /* value = -1 means cache not used yet */
|
||||
cache[i].w = 0;
|
||||
}
|
||||
(blank = cache + n_rec)->v = 0;
|
||||
return 1;
|
||||
int *knapsack (int w) {
|
||||
int i, j, k, v, *mm, **m, *s;
|
||||
mm = calloc((n + 1) * (w + 1), sizeof (int));
|
||||
m = malloc((n + 1) * sizeof (int *));
|
||||
m[0] = mm;
|
||||
for (i = 1; i <= n; i++) {
|
||||
m[i] = &mm[i * (w + 1)];
|
||||
for (j = 0; j <= w; j++) {
|
||||
m[i][j] = m[i - 1][j];
|
||||
for (k = 1; k <= items[i - 1].count; k++) {
|
||||
if (k * items[i - 1].weight > j) {
|
||||
break;
|
||||
}
|
||||
v = m[i - 1][j - k * items[i - 1].weight] + k * items[i - 1].value;
|
||||
if (v > m[i][j]) {
|
||||
m[i][j] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s = calloc(n, sizeof (int));
|
||||
for (i = n, j = w; i > 0; i--) {
|
||||
int v = m[i][j];
|
||||
for (k = 0; v != m[i - 1][j] + k * items[i - 1].value; k++) {
|
||||
s[i - 1]++;
|
||||
j -= items[i - 1].weight;
|
||||
}
|
||||
}
|
||||
free(mm);
|
||||
free(m);
|
||||
return s;
|
||||
}
|
||||
|
||||
solution solve(int weight, int pos)
|
||||
{
|
||||
int i, w, v, qty;
|
||||
solution sol, best = 0, ret;
|
||||
|
||||
if (pos < 0) return blank;
|
||||
|
||||
ret = &cache[weight * n_types + pos];
|
||||
if (ret->v >= 0) return ret;
|
||||
|
||||
w = items[pos].w;
|
||||
v = items[pos].v;
|
||||
qty = items[pos].qty;
|
||||
|
||||
for (i = 0; i <= qty && weight >= 0; i++, weight -= w) {
|
||||
sol = solve(weight, pos - 1);
|
||||
if (sol->v + i * v <= ret->v) continue;
|
||||
|
||||
best = sol;
|
||||
ret->v = best->v + v * i;
|
||||
ret->n[pos] = i;
|
||||
}
|
||||
|
||||
/* only happens if there are no solution at all, i.e.
|
||||
* max_weight too small to hold even one item
|
||||
*/
|
||||
if (ret->v <= 0) return blank;
|
||||
|
||||
ret->w = best->w + w * ret->n[pos];
|
||||
memcpy(ret->n, best->n, sizeof(unsigned short) * pos);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
solution x;
|
||||
|
||||
init_cache();
|
||||
x = solve(max_weight, n_types - 1);
|
||||
|
||||
printf("Taking:\n");
|
||||
for (i = 0; i < n_types; i++) {
|
||||
if (! x->n[i]) continue;
|
||||
printf(" %hu %s\n", x->n[i], items[i].name);
|
||||
}
|
||||
|
||||
printf("Weight: %d Value: %d\n", x->w, x->v);
|
||||
|
||||
/* free(cache); */
|
||||
return 0;
|
||||
int main () {
|
||||
int i, tc = 0, tw = 0, tv = 0, *s;
|
||||
s = knapsack(400);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (s[i]) {
|
||||
printf("%-22s %5d %5d %5d\n", items[i].name, s[i], s[i] * items[i].weight, s[i] * items[i].value);
|
||||
tc += s[i];
|
||||
tw += s[i] * items[i].weight;
|
||||
tv += s[i] * items[i].value;
|
||||
}
|
||||
}
|
||||
printf("%-22s %5d %5d %5d\n", "count, weight, value:", tc, tw, tv);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
(ns knapsack
|
||||
(:gen-class))
|
||||
|
||||
(def groupeditems [
|
||||
["map", 9, 150, 1]
|
||||
["compass", 13, 35, 1]
|
||||
["water", 153, 200, 3]
|
||||
["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]
|
||||
])
|
||||
|
||||
(defstruct item :name :weight :value)
|
||||
|
||||
(def items (->> (for [[item wt val n] groupeditems]
|
||||
(repeat n [item wt val]))
|
||||
(mapcat identity)
|
||||
(map #(apply struct item %))
|
||||
(vec)))
|
||||
|
||||
(declare mm) ;forward decl for memoization function
|
||||
(defn m [i w]
|
||||
(cond
|
||||
(< i 0) [0 []]
|
||||
(= w 0) [0 []]
|
||||
:else
|
||||
(let [{wi :weight vi :value} (get items i)]
|
||||
(if (> wi w)
|
||||
(mm (dec i) w)
|
||||
(let [[vn sn :as no] (mm (dec i) w)
|
||||
[vy sy :as yes] (mm (dec i) (- w wi))]
|
||||
(if (> (+ vy vi) vn)
|
||||
[(+ vy vi) (conj sy i)]
|
||||
no))))))
|
||||
|
||||
(def mm (memoize m))
|
||||
|
||||
(let [[value indexes] (mm (-> items count dec) 400)
|
||||
names (map (comp :name items) indexes)]
|
||||
(println "Items to pack:")
|
||||
(doseq [[k v] (frequencies names)]
|
||||
(println (format "%d %s" v k)))
|
||||
(println "Total value:" value)
|
||||
(println "Total weight:" (reduce + (map (comp :weight items) indexes))))
|
||||
|
|
@ -64,7 +64,7 @@ sub pick {
|
|||
}]}
|
||||
}
|
||||
|
||||
my ($v, $w, $p) = pick(400, $#items);
|
||||
my ($v, $w, $p) = pick($max_weight, $#items);
|
||||
for (0 .. $#$p) {
|
||||
if ($p->[$_] > 0) {
|
||||
print "$p->[$_] of $items[$_]{name}\n";
|
||||
|
|
|
|||
|
|
@ -25,28 +25,25 @@ knapsack :-
|
|||
( socks, 4, 50, 1),
|
||||
( book, 30, 10, 2)],
|
||||
|
||||
% R is the list of the numbers of each items
|
||||
% Takes is the list of the numbers of each items
|
||||
% these numbers are between 0 and the 4th value of the tuples of the items
|
||||
maplist(create_lists,L, R, LW, LV),
|
||||
sum(LW, #=<, 400),
|
||||
sum(LV, #=, VM),
|
||||
maplist(collect, L, Ws, Vs, Takes),
|
||||
scalar_product(Ws, Takes, #=<, 400),
|
||||
scalar_product(Vs, Takes, #=, VM),
|
||||
|
||||
% to have statistics on the resolution of the problem.
|
||||
time(labeling([max(VM)], R)),
|
||||
sum(LW, #=, WM),
|
||||
time(labeling([max(VM), down], Takes)),
|
||||
scalar_product(Ws, Takes, #=, WM),
|
||||
|
||||
%% displayinf of the results.
|
||||
compute_lenword(L, 0, Len),
|
||||
sformat(A1, '~~w~~t~~~w|', [Len]),
|
||||
sformat(A2, '~~t~~w~~~w|', [4]),
|
||||
sformat(A3, '~~t~~w~~~w|', [5]),
|
||||
print_results(A1,A2,A3, L, R, WM, VM).
|
||||
print_results(A1,A2,A3, L, Takes, WM, VM).
|
||||
|
||||
|
||||
create_lists((_, W, V, N), C, LW, LV) :-
|
||||
C in 0..N,
|
||||
LW #= C * W,
|
||||
LV #= C * V.
|
||||
collect((_, W, V, N), W, V, Take) :-
|
||||
Take in 0..N.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
/* create SAS data set */
|
||||
data mydata;
|
||||
input item $1-23 weight value pieces;
|
||||
datalines;
|
||||
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
|
||||
;
|
||||
|
||||
/* call OPTMODEL procedure in SAS/OR */
|
||||
proc optmodel;
|
||||
/* declare sets and parameters, and read input data */
|
||||
set <str> ITEMS;
|
||||
num weight {ITEMS};
|
||||
num value {ITEMS};
|
||||
num pieces {ITEMS};
|
||||
read data mydata into ITEMS=[item] weight value pieces;
|
||||
|
||||
/* declare variables, objective, and constraints */
|
||||
var NumSelected {i in ITEMS} >= 0 <= pieces[i] integer;
|
||||
max TotalValue = sum {i in ITEMS} value[i] * NumSelected[i];
|
||||
con WeightCon:
|
||||
sum {i in ITEMS} weight[i] * NumSelected[i] <= 400;
|
||||
|
||||
/* call mixed integer linear programming (MILP) solver */
|
||||
solve;
|
||||
|
||||
/* print optimal solution */
|
||||
print TotalValue;
|
||||
print {i in ITEMS: NumSelected[i].sol > 0.5} NumSelected;
|
||||
quit;
|
||||
Loading…
Add table
Add a link
Reference in a new issue