Prolog正确的多米诺骨牌选择

时间:2017-03-20 18:48:42

标签: prolog clpfd

d(2,6)是一张多米诺骨牌。

我遇到了检查是否有多米诺骨牌列表的问题 通过重新排列列表中的元素以及通过重新组合来成功地连接在一起 交换单个多米诺骨牌。 例如,以下选择有效

?- playout([d(3,6),d(0,4),d(3,4),d(1,3),d(1,6),d(0,1),d(4,4)]).

true.

因为可以安排

[d(1,0),d(0,4),d(4,4),d(4,3),d(3,6),d(6,1),d(1,3)]

但是下面的选择不起作用

?- playout([d(0,3),d(1,2),d(5,6),d(5,5),d(0,2),d(0,5),d(3,5)]).

false.

1 个答案:

答案 0 :(得分:2)

这是一个非常有趣的组合任务,超过整数,非常适合Prolog的 CLP(FD)约束

这是一个解决方案,适用于SICStus Prolog,SWI和YAP下的大多数小修改:

:- use_module(library(clpfd)).

dominos_arrangement(Ds, Solution, Vs) :-
        same_length(Ds, As),
        dominos_tuples(Ds, Ts),
        phrase(dominos_ids(As, IDs), Vs),
        tuples_in(As, Ts),
        As = [First|Rest],
        foldl(linked_domino, Rest, First, _),
        all_distinct(IDs),
        maplist(domino_triple, Solution, As).

linked_domino([Val,Next,_], Prev, [_,Next,_]) :-
        Prev = [_,Val,_].

dominos_ids([], []) --> [].
dominos_ids([[X,Y,ID]|Ds], [ID|IDs]) -->
        [X,Y,ID],
        dominos_ids(Ds, IDs).

dominos_tuples(Ds, Ts) :-
        phrase(dominos_tuples_(Ds, 0), Ts).

dominos_tuples_([], _) --> [].
dominos_tuples_([d(X,Y)|Ds], ID0) -->
        [[X,Y,ID0],[Y,X,ID0]],
        { ID #= ID0 + 1 },
        dominos_tuples_(Ds, ID).

domino_triple(d(X,Y), [X,Y,_]).

使用您的示例,我们已经可以使用最常见的查询来查看核心关系是否按预期终止:

?- Ds = [d(3,6),d(0,4),d(3,4),d(1,3),d(1,6),d(0,1),d(4,4)],
   dominos_arrangement(Ds, As, Vs).
Ds = [d(3, 6), d(0, 4), d(3, 4), d(1, 3), d(1, 6), d(0, 1), d(4, 4)],
As = [d(_3398, _3400), d(_3400, _3412), d(_3412, _3424), d(_3424, _3436), d(_3436, _3448), d(_3448, _3460), d(_3460, _3472)],
Vs = [_3398, _3400, _3500, _3400, _3412, _3518, _3412, _3424, _3536|...],
_3398 in 0..1\/3..4\/6,
etc.

是的,这看起来非常好。注意变量别名如何将链链接在一起

为了制作具体的解决方案,我们在变量列表中使用标记

?- Ds = [d(3,6),d(0,4),d(3,4),d(1,3),d(1,6),d(0,1),d(4,4)],
   dominos_arrangement(Ds, As, Vs),
   label(Vs).
Ds = [d(3, 6), d(0, 4), d(3, 4), d(1, 3), d(1, 6), d(0, 1), d(4, 4)],
As = [d(1, 0), d(0, 4), d(4, 4), d(4, 3), d(3, 1), d(1, 6), d(6, 3)],
Vs = [1, 0, 5, 0, 4, 1, 4, 4, 6|...] ;
Ds = [d(3, 6), d(0, 4), d(3, 4), d(1, 3), d(1, 6), d(0, 1), d(4, 4)],
As = [d(1, 0), d(0, 4), d(4, 4), d(4, 3), d(3, 6), d(6, 1), d(1, 3)],
Vs = [1, 0, 5, 0, 4, 1, 4, 4, 6|...] ;
Ds = [d(3, 6), d(0, 4), d(3, 4), d(1, 3), d(1, 6), d(0, 1), d(4, 4)],
As = [d(1, 3), d(3, 4), d(4, 4), d(4, 0), d(0, 1), d(1, 6), d(6, 3)],
Vs = [1, 3, 3, 3, 4, 2, 4, 4, 6|...] ;
Ds = [d(3, 6), d(0, 4), d(3, 4), d(1, 3), d(1, 6), d(0, 1), d(4, 4)],
As = [d(1, 3), d(3, 6), d(6, 1), d(1, 0), d(0, 4), d(4, 4), d(4, 3)],
Vs = [1, 3, 3, 3, 6, 0, 6, 1, 4|...] ;
Ds = [d(3, 6), d(0, 4), d(3, 4), d(1, 3), d(1, 6), d(0, 1), d(4, 4)],
As = [d(1, 6), d(6, 3), d(3, 1), d(1, 0), d(0, 4), d(4, 4), d(4, 3)],
Vs = [1, 6, 4, 6, 3, 0, 3, 1, 3|...] ;
etc.

在回溯时,会生成所有解决方案。

请注意在这种情况下约束求解的通常优势,例如搜索空间的重要修剪,这使得无需详尽地尝试所有组合,并且有可能通过尝试更智能的搜索策略标签选项。