排列的列表,数字必须更改其在Prolog中的位置

时间:2019-03-22 15:54:17

标签: prolog

我正在尝试为我的任务解决这个问题。

仅当R代表列表L的可接受置换时,谓词acceptable_permutation(L,R)才应成功。 例如:[2,1,3]不是列表[1,2,3]的可接受排列,因为3并未改变其位置。

输出为 假定 ,如下所示:

?- acceptable_permutation([1,2,3],R).
R = [2,3,1] ;
R = [3,1,2] ;
false

?- acceptable_permutation([1,2,3,4],R).
R = [2,1,4,3] ;
R = [2,3,4,1] ;
R = [2,4,1,3] ;
R = [3,1,4,2] ;
R = [3,4,1,2] ;
R = [3,4,2,1] ;
R = [4,1,2,3] ;
R = [4,3,1,2] ;
R = [4,3,2,1] ;
false.

我的代码输出给出:

?- acceptable_permutation([1,2,3],R).
R = [1,2,3] ;
R = [1,3,2] ;
R = [2,1,3] ;
R = [2,3,1] ;
R = [3,1,2] ;
R = [3,2,1] ;

?- acceptable_permutation([1,2,3,4],R).
R = [1,2,3,4] ;
R = [1,2,4,3] ;
R = [1,3,2,4] ;
R = [1,3,4,2] ;
R = [1,4,2,3] ;
R = [1,4,3,2] ;
R = [2,1,3,4] ;
R = [2,1,4,3] ;
R = [2,3,1,4] ;
R = [2,3,4,1] ;
R = [2,4,1,3] ;
R = [2,4,3,1] ;
R = [3,1,2,4] ;
R = [3,1,4,2] ;
R = [3,2,1,4] ;
R = [3,2,4,1] ;
R = [3,4,1,2] ;
R = [3,4,2,1] ;
R = [4,1,2,3] ;
R = [4,1,3,2] ;
R = [4,2,1,3] ;
R = [4,2,3,1] ;
R = [4,3,1,2] ;
R = [4,3,2,1] ;
false.

我的代码如下:

acceptable_permutation(list,list).

del(symbol,list,list).

del(X,[X|L1], L1).

del(X,[Y|L1], [Y|L2]):-
    del(X,L1, L2).
    acceptable_permutation([] , []).

acceptable_permutation(L, [X|P]):-
    del(X, L, L1),
    acceptable_permutation(L1, P).

请告诉我问题出在哪里,这样我的输出应与正确的输出匹配。如果您向我展示它是如何完成的,我将不胜感激。

2 个答案:

答案 0 :(得分:2)

1)没有固定点的置换称为derangement。好笑的名字!也是这样。

2)previous answer一样,我们使用maplist/3permutation/2

3)与此previous answer不同,我们使用而不是(\=)/2 来保持逻辑纯洁

有助于保持Prolog程序的通用性,在这种情况下,还可以提高效率

让我们像这样定义list_derangement/2

list_derangement(Es, Xs) :-
   maplist(dif, Es, Xs),         % using dif/2
   permutation(Es, Xs).

请注意,maplist/2目标现在位于另一个目标之前!

与先前答案中的find_perm/2相比,这可以加快失败案例的检测速度:

?- time(find_perm([1,2,3,4,5,6,7,8,9,10,11],
                  [_,_,_,_,_,_,_,_,_, _,11])).
% 303,403,801 inferences, 37.018 CPU in 37.364 seconds (99% CPU, 8196109 Lips)  
false.

?- time(list_derangement([1,2,3,4,5,6,7,8,9,10,11], 
                         [_,_,_,_,_,_,_,_,_, _,11])).
% 15,398 inferences, 0.009 CPU in 0.013 seconds (67% CPU, 1720831 Lips)         
false.

对于相应的地面术语,上述实现的速度相当:

?- time((find_perm([1,2,3,4,5,6,7,8,9,10,11],_),false)).
% 931,088,992 inferences, 107.320 CPU in 107.816 seconds (100% CPU, 8675793 Lips)
false.

?- time((list_derangement([1,2,3,4,5,6,7,8,9,10,11],_),false)).
% 1,368,212,629 inferences, 97.890 CPU in 98.019 seconds (100% CPU, 13976991 Lips)
false.

答案 1 :(得分:0)

问题是您没有检查输出列表的所有元素与输入列表的位置是否不同。您应该添加一个谓词来检查它,就像这样:

perm(L,LO):-
    acceptable_permutation(L,LO),
    different_place(L,LO).

different_place([A|T0],[B|T1]):-
    A \= B,
    different_place(T0,T1).
different_place([],[]).

?- perm([1,2,3],R).
R = [2, 3, 1]
R = [3, 1, 2]
false

改进1:您可以通过以下方式将different_place/2maplist/3结合使用,而不是创建自己的谓词(在本例中为\=/2):

perm(L,LO):-
    acceptable_permutation(L,LO),
    maplist(\=,L,LO).

改进2:swi序言提供了谓词permutation/2,该谓词计算列表的排列。因此,您只需三行即可解决您的问题:

find_perm(L,LO):-
    permutation(L,LO),
    maplist(\=,L,LO).

?- find_perm([1,2,3],L).
L = [2, 3, 1]
L = [3, 1, 2]
false