有条件的Prolog排列?

时间:2016-01-08 22:30:04

标签: algorithm list prolog conditional-statements permutation

我有这个程序来生成列表的所有排列。问题是,我只需要生成连续项的绝对差值小于或等于3的排列。例如:

[2,7,5] => [2,5,7][7,5,2]。自[2 7 5]2-7 = -5

以来,|-5| > 3会出错

排列计划:

perm([X|Y],Z):-
    perm(Y,W),
    takeout(X,Z,W).
perm([],[]).

takeout(X,[X|R],R).
takeout(X,[F|R],[F|S]):-
    takeout(X,R,S).

permutfin(X,R):-
    findall(P,perm(X,P),R).

我知道我应该在perm函数的某处添加条件,但我无法确切地知道写什么或在哪里写。

2 个答案:

答案 0 :(得分:3)

编写排列的更直观的方法是:

takeout([X|T],X,T).
takeout([H|L],X,[H|T]) :-
    takeout(L,X,T).

第一个元素是原始列表,第二个元素是选中的元素,第三个元素是没有该元素的列表。

在这种情况下,置换谓词定义为:

perm([],[]).
perm(L,[E|T]) :-
    takeout(L,E,R),
    perm(R,T).

这也允许尾递归,这可能意味着在大多数Prolog系统中都有重要的优化。

现在,为了只生成连续差异最多为3的排列,你可以做两件事:

  • 天真的方式是生成并测试:在这里你让Prolog产生一个排列,但是你只有在满足某个条件时才接受它。例如:

    dif3([_]).
    dif3([A,B|T]) :-
        D is abs(A-B),
        D =< 3,
        dif3([B|T]).
    

    然后定义:

    perm3(L,R) :-
        perm(L,R),
        dif3(R).
    

    这种方法效率不高:对于指数量的排列,只有少数是有效的,这意味着需要大量的计算工作。例如,如果元素列表为[2,5,7,9],它将生成以[2,9,...]开头的所有排列,而更智能的方法可能已经看到无论如何都不会生成有效的解决方案。

  • 另一种更智能的方法是交错生成和测试。在这里,您只选择takeout3/4个有效候选人的数字。您可以定义谓词takeout3(L,P,X,T).,其中L是原始列表,P是前一个号码,X所选号码和T结果列表:

    takeout3([X|T],P,X,T) :-
        D is abs(X-P),
        D =< 3.
    takeout3([H|L],N,X,[H|T]) :-
        takeout3(L,N,X,T).
    

    现在我们可以按如下方式生成排列:

    perm3([],[]).
    perm3(L,[E|T]) :-
        takeout(L,E,R),
        perm3(R,E,T).
    
    perm3([],_,[]).
    perm3(L,O,[E|T]) :-
        takeout3(L,O,E,R),
        perm3(R,E,T).
    

    请注意,我们使用两个版本的perm3perm3/2perm3/3,第一个用于生成第一个元素(使用旧的takeout/3)和{{ 1}}用于使用perm3/3生成排列的其余部分。

    这种方法的完整源代码是:

    takeout3/4

    使用takeout([X|T],X,T). takeout([H|L],X,[H|T]) :- takeout(L,X,T). takeout3([X|T],P,X,T) :- D is abs(X-P), D =< 3. takeout3([H|L],N,X,[H|T]) :- takeout3(L,N,X,T). perm3([],[]). perm3(L,[E|T]) :- takeout(L,E,R), perm3(R,E,T). perm3([],_,[]). perm3(L,O,[E|T]) :- takeout3(L,O,E,R), perm3(R,E,T). 运行它:

    swipl

    预期的行为。

答案 1 :(得分:3)

这是另一种解决方案。我在takeout中添加了条件,以确保相邻项目彼此相差3个以上:

perm([X|Y],Z):-
    perm(Y,W),
    takeout(X,Z,W).
perm([],[]).

check(_,[]).
check(X,[H|_]) :-
    D is X - H,
    D < 4,
    D > -4.

takeout(X,[X|R],R) :-
    check(X,R).
takeout(X,[F|R],[F|S]):-
    takeout(X,R,S),
    check(F,R).