List 具有多个相同元素的列表排列Prolog
大家好,请原谅任何误用语言的行为 我需要创建我的置换(L1,L2)。给定一个列表L1(其中包含具有许多相关外观的元素)返回一个列表L2,该列表L1的排序方式是没有两个相同的相关元素) 示例:给定列表L1[1,1,1,1,2,2,3,3,4,4,5,5],L2应该是[1,2,1,5,1,3,1,4,1,2,3,5,4] 我尝试过随机排列并检查每个排列的一致性,但速度非常慢(对于超过12个元素的L1,大约24个CPU) 唯一可能的解决方案是进行一致的排列,而不是检查一个 但是我该怎么做呢 即使使用标准的prolog也可能做到这一点,但由于我对逻辑编程的理解不够透彻,我无法理解它List 具有多个相同元素的列表排列Prolog,list,prolog,permutation,prolog-dif,dif,meta-predicate,List,Prolog,Permutation,Prolog Dif,Dif,Meta Predicate,大家好,请原谅任何误用语言的行为 我需要创建我的置换(L1,L2)。给定一个列表L1(其中包含具有许多相关外观的元素)返回一个列表L2,该列表L1的排序方式是没有两个相同的相关元素) 示例:给定列表L1[1,1,1,1,2,2,3,3,4,4,5,5],L2应该是[1,2,1,5,1,3,1,4,1,2,3,5,4] 我尝试过随机排列并检查每个排列的一致性,但速度非常慢(对于超过12个元素的L1,大约24个CPU) 唯一可能的解决方案是进行一致的排列,而不是检查一个 但是我该怎么做呢 即使使用标
谢谢:D您可以在列表中构建这样的排列
myPermutation([], []).
myPermutation(L, [H|P]):-
select(H, L, NL), % Select one item from the list
myPermutation(NL, H, P).
myPermutation([], _, []).
myPermutation(L, H, [I|P]):-
select(I, L, NL), % Select another item
I \= H, % Enforce restriction of no duplicate consecutive items
myPermutation(NL, I, P).
此代码将在回溯时提供所有有效排列。作为练习,我将向您介绍一种放弃重复排列的方法。您可以使用
dif/2
快速完成此操作,它将两个变量约束为具有不同的值,而事先不知道这些值:
?- dif(X,Y).
dif(X, Y).
?- dif(X,Y), X=1.
X = 1,
dif(1, Y).
?- dif(X,Y), X=1, Y=1.
false.
使用此选项,您可以创建一个谓词来约束列表,以确保没有两个元素是相同的:
conseq_dif([]).
conseq_dif([_]).
conseq_dif([X,Y|Xs]) :-
dif(X,Y),
conseq_dif([Y|Xs]).
现在要查找所需的受约束排列:
constrained_perm(Lst,Prm) :-
length(Lst,N),
length(Prm,N), % make list of N unbound variables
conseq_dif(Prm),
permutation(Lst,Prm). % "ordinary" (library) permutation finding
我不确定dif/2是否是标准Prolog,但主要的实现都有它。我们基于, ,和
mapadj/2
:
my_perm(Xs,Ys) :-
same_length(Xs,Ys),
mapadj(dif,Ys),
list_permuted(Xs,Ys).
通用的mapadj/2
可以这样定义:
:- meta_predicate mapadj(2,?), list_mapadj(?,2), list_prev_mapadj(?,?,2).
mapadj(P_2,Xs) :-
list_mapadj(Xs,P_2).
list_mapadj([],_).
list_mapadj([A|As],P_2) :-
list_prev_mapadj(As,A,P_2).
list_prev_mapadj([],_,_).
list_prev_mapadj([A1|As],A0,P_2) :-
call(P_2,A0,A1),
list_prev_mapadj(As,A1,P_2).
下面是OP给出的示例查询1,2 我们使用以毫秒为单位测量运行时间
T\u ms
?- call_time(my_perm([1,1,1,1,1,2,2,3,3,4,4,5,5],[1,2,1,5,1,3,1,4,1,2,3,5,4]),T_ms).
T_ms = 0.
我们需要多长时间才能找到最初的几个解决方案
?- call_time(my_perm([1,2,1,5,1,3,1,4,1,2,3,5,4],Xs),T_ms).
T_ms = 0, Xs = [1,2,1,5,1,3,1,4,1,2,3,5,4]
; T_ms = 0, Xs = [1,2,1,5,1,3,1,4,1,2,3,4,5]
; T_ms = 10, Xs = [1,2,1,5,1,3,1,4,1,2,5,3,4]
; T_ms = 10, Xs = [1,2,1,5,1,3,1,4,1,2,4,3,5]
; T_ms = 10, Xs = [1,2,1,5,1,3,1,4,1,2,5,4,3]
; T_ms = 10, Xs = [1,2,1,5,1,3,1,4,1,2,4,5,3]
; T_ms = 10, Xs = [1,2,1,5,1,3,1,4,1,3,2,5,4]
; T_ms = 20, Xs = [1,2,1,5,1,3,1,4,1,3,2,4,5]
; T_ms = 20, Xs = [1,2,1,5,1,3,1,4,1,5,2,3,4]
; T_ms = 20, Xs = [1,2,1,5,1,3,1,4,1,4,2,3,5]
; T_ms = 20, Xs = [1,2,1,5,1,3,1,4,1,5,2,4,3]
; T_ms = 20, Xs = [1,2,1,5,1,3,1,4,1,4,2,5,3]
; T_ms = 20, Xs = [1,2,1,5,1,3,1,4,1,3,5,2,4]
; T_ms = 20, Xs = [1,2,1,5,1,3,1,4,1,3,4,2,5]
; T_ms = 20, Xs = [1,2,1,5,1,3,1,4,1,5,3,2,4]
; T_ms = 20, Xs = [1,2,1,5,1,3,1,4,1,4,3,2,5]
; T_ms = 30, Xs = [1,2,1,5,1,3,1,4,1,5,4,2,3]
; T_ms = 30, Xs = [1,2,1,5,1,3,1,4,1,4,5,2,3]
...
请注意,T_ms
是单调增长的:它度量自第一次调用给定目标以来所花费的时间
列举所有解决方案需要多长时间
?- call_time(\+((my_perm([1,1,1,1,1,2,2,3,3,4,4,5,5],_),false)),T_ms).
T_ms = 4030.
有多少种解决方案
?- use_module(library(aggregate)),
aggregate(count,Xs,my_perm([1,2,1,5,1,3,1,4,1,2,3,5,4],Xs),N).
N = 197664.
脚注1:使用SICStus Prolog版本4.3.2(x86_64-linux-glibc2.12)。
脚注2:为了可读性,Prolog处理器给出的答案序列已经过调整。
排列方式是否应该避免“重复”包含与另一个解决方案相同的相同项目的解决方案?这是我想到的第一件要担心的事。避免解决方案序列中的“重复”似乎是对通常的“排列”谓词的一个相当简单的修改+我发布了一个基于
dif/2
goal\u rt/2
不嵌套的新备选方案。请这样做。