在列表序言中创建数字组合

时间:2014-12-12 18:52:12

标签: algorithm prolog constraints clpfd

我正在PROLOG(有限制)开发一个程序,该程序应该在某些限制内输出6个数字的组合。

列表必须从1到4的数字,因此,将重复2个其他数字。 可能的数字从1到4。

Possible examples:     Wrong examples:
1,2,3,4,1,1            1,2,3,2,3,3 //Missing #4
1,3,2,1,4,4            4,3,2,4,2,3 //Missing #1
1,2,3,3,2,4
4,1,3,2,1,4

为了完成这项工作,我创建了一些限制,如下所示:

Numbers = [A1, A2, A3, A4, A5, A6]
nCr(6,4) = 15 restrictions
A1 =\= A2 =\= A3 =\= A4 OR
A1 =\= A2 =\= A3 =\= A5 OR
Etc.

这是我迄今为止开发的代码:

make

pred(Numbers) :-

       Numbers = [A1, A2, A3, A4, A5, A6],
       domain(Numbers, 1, 4),

       %restrictions
       all_different([A1,A2,A6,A3]) #\/    %A1 =/= A2 =/= A6 =/= A3
        all_different([A1,A2,A6,A4]) #\/    %A1 =/= A2 =/= A6 =/= A4
         all_different([A1,A2,A6,A5]) #\/    %A1 =/= A2 =/= A6 =/= A5
          all_different([A1,A2,A3,A4]) #\/    %A1 =/= A2 =/= A3 =/= A4
           all_different([A1,A2,A3,A5]) #\/    %A1 =/= A2 =/= A3 =/= A5
            all_different([A1,A2,A4,A5]) #\/    %A1 =/= A2 =/= A4 =/= A5
             all_different([A1,A6,A3,A4]) #\/    %A1 =/= A6 =/= A3 =/= A4
              all_different([A1,A6,A3,A5]) #\/    %A1 =/= A6 =/= A3 =/= A5
               all_different([A1,A6,A4,A5]) #\/    %A1 =/= A6 =/= A4 =/= A5
                all_different([A1,A3,A5,A4]) #\/    %A1 =/= A3 =/= A4 =/= A5
                 all_different([A2,A6,A3,A4]) #\/    %A2 =/= A6 =/= A3 =/= A4
                  all_different([A2,A6,A3,A5]) #\/    %A2 =/= A6 =/= A3 =/= A5 
                   all_different([A2,A6,A4,A5]) #\/    %A2 =/= A6 =/= A4 =/= A5
                    all_different([A2,A3,A4,A5]) #\/    %A2 =/= A3 =/= A4 =/= A5 
                     all_different([A6,A3,A4,A5]),    %A6 =/= A3 =/= A4 =/= A5

           labeling([], Numbers).

逻辑对我来说似乎很好,但是这个实现并没有按预期工作。有无解决方案符合键入的限制。任何人都可以帮我一把吗?

| ?- pred([A1, A2, A3, A4, A5, A6]).
no

3 个答案:

答案 0 :(得分:6)

此查询应满足您的要求

?- Vs = [_,_,_,_,_,_], Vs ins 1..4,
   [A,B,C,D] ins 1..2, global_cardinality(Vs, [1-A,2-B,3-C,4-D]), label(Vs).
Vs = [1, 1, 2, 2, 3, 4],
A = B, B = 2,
C = D, D = 1 ;
Vs = [1, 1, 2, 2, 4, 3],
A = B, B = 2,
C = D, D = 1 ;
...

答案 1 :(得分:2)

以下是使用clpfd约束的两个替代查询:

  1. 使用nvalue/2约束,可与SICStus Prolog一起使用:

    ?- Vs = [_,_,_,_,_,_], domain(Vs,1,4),
       nvalue(4,Vs),
       labeling([],Vs).
    
  2. 使用element/3约束,nth1/3member/2的clpfd 兄弟

    ?- Vs = [_,_,_,_,_,_], domain(Vs,1,4),
       element(_,Vs,1),element(_,Vs,2),element(_,Vs,3),element(_,Vs,4),
       labeling([],Vs).
    
  3. 两个查询都提供相同的解决方案序列:

    Vs = [1,1,1,2,3,4] ? ;
    Vs = [1,1,1,2,4,3] ? ;
    Vs = [1,1,1,3,2,4] ? ;
    Vs = [1,1,1,3,4,2] ? ;
    Vs = [1,1,1,4,2,3] ? ;
    Vs = [1,1,1,4,3,2] ? ...
    

    上面的列表仅包含前几个结果,总共有1560个结果。

答案 2 :(得分:1)

请考虑更具说明性的编程风格。另一种解决方案如下:

pred(NumberList) :-
    NumberList =[_,_,_,_,_,_],
    member(1, NumberList),
    member(2, NumberList),
    member(3, NumberList),
    member(4, NumberList),
    member(A, [1,2,3,4]),
    member(B, [1,2,3,4]),
    member(A, NumberList),
    member(B, NumberList),
    forall(member(X, NumberList), number(X)).

该条款规定:

  • 列表的长度必须为6个元素
  • 1,2,3,4是列表中的所有元素
  • 列表中可能还有其他1,2,3,4部分
  • 并且所有成员都必须是数字。

需要forall的原因是,[1,2,3,4,]等解决方案会满足预测谓词。

最后一点是'pred'不是这种谓语的正确名称。