我想知道是否有办法解决CLP(B)中的背包问题。 CLP(B)似乎是合适的,因为打包项目可以建模为布尔变量。
示例:
x1,x2,x3,x4,x5 e {0,1}
x1 * 12 + x2 * 2 + x3 * 1 + x4 * 1 + x5 * 4 = <15
最大化x1 * 4 + x2 * 2 + x3 * 2 + x4 * 1 + x5 * 10
我对于如何制定背包容量有限的副作用感到有些困惑。 SWI-Prolog似乎具有weighted_maximum / 3,可以进行优化。
答案 0 :(得分:2)
您可以通过发布新变量来计算重量来对尺寸(重量)约束进行建模,然后使用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.
答案 1 :(得分:1)
我最近在我的CLP(B)中添加了一个约束伪/ 4,类似于来自CLP(FD)的约束scalar_product / 4,它不会创建电路,而是以更传统的方式维护约束。代码如下:
knapsack([X1,X2,X3,X4,X5], M) :-
pseudo([12,2,1,1,4], [X1,X2,X3,X4,X5], =<, 15),
weighted_maximum([4,2,2,1,10], [X1,X2,X3,X4,X5], M).
我与card / 2的配方进行了比较。与伪/ 4公式不同,card / 2公式将在引擎盖下创建电路。我的系统和SWI-Proilog都是这种情况:
knapsack3([X1,X2,X3,X4,X5], M) :-
sat(card([0-15],[X1,X1,X1,X1,X1,X1,X1,X1,X1,X1,X1,X1,X2,X2,X3,X4,X5,X5,X5,X5])),
weighted_maximum([4,2,2,1,10], [X1,X2,X3,X4,X5], M).
我做了一些测试,还测量了模型的建立时间。在本示例中,新的伪/ 4约束似乎是赢家。这是我系统中的结果:
Jekejeke Prolog 3, Runtime Library 1.3.8 (May 23, 2019)
?- time((between(1,100,_), knapsack(_,_), fail; true)).
% Up 95 ms, GC 3 ms, Thread Cpu 93 ms (Current 07/05/19 20:03:05)
Yes
?- time((between(1,100,_), knapsack3(_,_), fail; true)).
% Up 229 ms, GC 5 ms, Thread Cpu 219 ms (Current 07/05/19 20:02:58)
Yes
这是SWI-Prolog中的结果:
?- time((between(1,100,_), knapsack3(_,_), fail; true)).
% 8,229,000 inferences, 0.656 CPU in 0.656 seconds (100% CPU, 12539429 Lips)