prolog中的互斥事件

时间:2018-04-30 17:54:00

标签: prolog probability

我想在prolog中定义事件,如果一个事件发生,另一个则不能。

例如我有5个不同尺寸的盒子,比如说50,50,50,80,90平方厘米,还有4个存储空间,如果我把一个盒子放在一个存储空间中,我希望它不能存储两次。此外,我希望存储的整体大小为230.所以实际上,我想计算可能发生的所有可能情况以及哪个存储空间位于哪个存储空间。

关于如何做到这一点的任何想法?

2 个答案:

答案 0 :(得分:1)

我会使用术语和存储例程对此进行建模,如下所示:

% this is a start state
start(storage(empty, empty, empty, empty)).

这为您提供了4个存储空间。现在你需要一个插入它们的规则。

store(BoxSize, storage(empty, S2, S3, S4), storage(BoxSize, S2, S3, S4)).
store(BoxSize, storage(S1, empty, S3, S4), storage(S1, BoxSize, S3, S4)).
store(BoxSize, storage(S1, S2, empty, S4), storage(S1, S2, BoxSize, S4)).
store(BoxSize, storage(S1, S2, S3, empty), storage(S1, S2, S3, BoxSize)).

这定义store/3,它采用一个新框(由其大小表示)和4个存储空间的结构,并将该框放在存储空间的下一个空框中。

现在,您可以非常轻松地总结您使用的空间:

total(storage(S1, S2, S3, S4), Total) :-
    findall(N, (member(N, [S1, S2, S3, S4]), number(N)), Sizes),
    sumlist(Sizes, Total).

Total is S1+S2+S3+S4很有吸引力,但如果任何垃圾箱为空,则会失败。

这就是你如何使用我们迄今为止构建的内容:

?- start(Store), store(40, Store, NewStore), 
   store(50, NewStore, NewerStore), total(NewerStore, Total).
Store = storage(empty, empty, empty, empty),
NewStore = storage(40, empty, empty, empty),
NewerStore = storage(40, 50, empty, empty),
Total = 90 ;
Store = storage(empty, empty, empty, empty),
NewStore = storage(40, empty, empty, empty),
NewerStore = storage(40, empty, 50, empty),
Total = 90 ;

正如您所看到的,我们能够将商品添加到商店,并通过在不同的插槽中移动垃圾箱来为我们提供替代解决方案。手动操纵状态并不是很有趣;你可能会把它写成一个折叠,或者用phrase/3来固定状态,这样你就不需要继续制作中间状态。

我不确定您要对五个项目列表做些什么。所以你可能必须从这里拿出它来弄清楚你想如何插入它们并满足你的约束。我猜你想用select/3做一些事情,你把它放在箱子里,弄大小,忘掉剩下的东西。

答案 1 :(得分:1)

我对这个问题的解释是,你正在寻找列表[50, 50, 50, 80, 90]中最多4个元素的所有元素排列,最多汇总230个。这里的解决方案是故意原始的,没有利用任何对称性,不是甚至数字50的多次出现相等。

因此,让我们从一个谓词开始,该谓词描述了具有有限大小的列表元素的这种排列。最简单的方法是使用DCG来定义它:

permuted_sublist(List, MaxLength, PermutedSublist) :-
    phrase(permuted_sublist(List, MaxLength), PermutedSublist).

permuted_sublist(_List, _N) -->
    [].
permuted_sublist(List, N) -->
    { N > 0 },
    { select(Element, List, List1) },
    [Element],
    { N1 is N - 1 },
    permuted_sublist(List1, N1).

一个微妙之处在于第一个子句的头部匹配任何长度,而不仅仅是0.如果我们为0添加_N,这个语法将描述长度的子列表完全给出的数字,但我们也希望允许更短的数字。

测试:

?- permuted_sublist([a, b, c, d, e], 2, Selection).
Selection = [] ;
Selection = [a] ;
Selection = [a, b] ;
Selection = [a, c] ;
Selection = [a, d] ;
Selection = [a, e] ;
Selection = [b] ;
Selection = [b, a] ;
Selection = [b, c] ;
Selection = [b, d] ;
Selection = [b, e] ;
Selection = [c] ;  % etc

鉴于此,我们只需要在总和上添加约束:

placement(Sizes, Selection, Sum) :-
    permuted_sublist(Sizes, 4, Selection),
    sumlist(Selection, Sum),
    Sum =< 230.

这表现如下:

?- placement([50, 50, 50, 80, 90], Placement, Sum).
Placement = [],
Sum = 0 ;
Placement = [50],
Sum = 50 ;
Placement = [50, 50],
Sum = 100 ;
Placement = [50, 50, 50],
Sum = 150 ;
Placement = [50, 50, 50, 80],
Sum = 230 ;
Placement = [50, 50, 80],
Sum = 180 ;
Placement = [50, 50, 80, 50],
Sum = 230 ;  % etc

同样,通过将select/3目标替换为append(_Prefix, [Element|List1], List),可以减少此类裁员。