Вы можете смоделировать ограничения размера (веса), введя новые переменные для учета веса, затем использовать ограничение card
для моделирования вместимости рюкзака и, наконец, использовать weighted_maximum/2
для максимизации цели:
:- use_module(library(clpb)).
knapsack_sample([X1,X2,X3,X4,X5], Maximum):-
knapsack([X1-12/4,X2-2/2,X3-1/2,X4-1/1,X5-4/10], 15, Maximum).
% Data is a list of BucketVar-Value/Weight
knapsack(Data, Capacity, Maximum):-
buckets(Data, [], [], Buckets, AndEqAll, Weights, Xs),
sat(card([0-Capacity], Buckets)),
sat(AndEqAll),
weighted_maximum(Weights, Xs, Maximum).
buckets([], [EqAll|LEqAll], LBuckets, Buckets, AndEqAll, [], []):-
foldl(andall, LEqAll, EqAll, AndEqAll),
append(LBuckets, Buckets).
buckets([X-Count/Weight|Counts], LEqAll, LBuckets, Buckets, AndEqAll, [Weight|Weights], [X|Xs]):-
length([B|Bs], Count),
foldl(eqall(X), Bs, (X=:=B), EqAll),
buckets(Counts, [EqAll|LEqAll], [[B|Bs]|LBuckets], Buckets, AndEqAll, Weights, Xs).
eqall(B, X, Y, (B=:=X)*Y).
andall(X, Y, X*Y).
Так что в вашем примере вы бы назвали рюкзак с Data=[X1-12/4,X2-2/2,X3-1/2,X4-1/1,X5-4/10]
и 15
емкостью:
?- knapsack([X1-12/4,X2-2/2,X3-1/2,X4-1/1,X5-4/10], 15, Maximum).
X1 = 0,
X2 = X3, X3 = X4, X4 = X5, X5 = 1,
Maximum = 15.
ОБНОВЛЕНИЕ:
На самом деле card
ограничения отлично справляются с повторениями, поэтому нет необходимости добавлять новые переменные, и решение становится проще:
knapsack2(Data, Capacity, Maximum):-
maplist(knap, Data, LBuckets, Weights, Xs),
append(LBuckets, Buckets),
sat(card([0-Capacity], Buckets)),
weighted_maximum(Weights, Xs, Maximum).
knap(X-Value/Weight, Ws, Weight, X):-
length(Ws, Value),
maplist(=(X), Ws).
Пример выполнения:
?- knapsack2([X1-12/4,X2-2/2,X3-1/2,X4-1/1,X5-4/10], 15, Maximum).
X1 = 0,
X2 = X3, X3 = X4, X4 = X5, X5 = 1,
Maximum = 15.