【问题标题】:Create combinations of numbers within list prolog在列表序言中创建数字组合
【发布时间】:2015-03-31 02:03:45
【问题描述】:

我正在用 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

【问题讨论】:

  • 尝试在更高级别表达限制。当你写它们时,它真的难以阅读......
  • 这是我试图解决的子问题,以便开发更大的程序,这就是代码还不漂亮的原因。反正我做了一些改变。
  • @Khabz:当您谈到“限制”时,您的意思是指限制吗?至少这是我在查看您的程序时认为是正确的。
  • @false:是的,我就是这个意思。 “Restrições”是葡萄牙语的名字,这就是我通常说限制的原因
  • @Khabz:在英语中是约束,在法语中是约束

标签: algorithm prolog constraints clpfd


【解决方案1】:

此查询应满足您的要求

?- 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 ;
...

【讨论】:

  • 我仍然想知道为什么我的解决方案没有奏效。这似乎合乎逻辑。
  • 加号! taceo nunc !
  • @repeat:谢谢,你是对的。也许 OP 只需要 global_cardinality 示例。
【解决方案2】:

这里有两个使用 clpfd 约束的替代查询:

  1. 使用 SICStus Prolog 提供的 nvalue/2 约束:

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

    ?- Vs = [_,_,_,_,_,_], domain(Vs,1,4),
       element(_,Vs,1),element(_,Vs,2),element(_,Vs,3),element(_,Vs,4),
       labeling([],Vs).
    

两个查询给出相同的解决方案序列:

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 个。

【讨论】:

    【解决方案3】:

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

    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”不是这样一个谓词的正确名称。

    【讨论】:

    • forall/2 和 number/1 是声明性的?
    • 我也想到了这个算法(+1 用于实现它),但 CapelliC 似乎是一个更好的解决方案。另外,那是复制粘贴的代码,稍作改动,原始名称根本不是随机的。
    猜你喜欢
    • 1970-01-01
    • 2022-12-20
    • 1970-01-01
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多