перестановка списка с несколькими одинаковыми элементами Пролог

привет всем, пожалуйста, простите за неправильное использование языка

мне нужно создать myPermutation (L1, L2). который с учетом списка L1 (который имеет элементы с множеством последовательных появлений) возвращает список L2, который является L1 отсортированным таким образом, что нет двух последовательных элементов, которые являются одинаковыми)

пример: учитывая список L1 [1,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] Я пробовал случайные перестановки и проверял каждую перестановку на согласованность, но это очень медленно (примерно 24 процессора для L1 с более чем 12 элементами)

единственное возможное решение - сделать последовательную перестановку вместо проверки одной, но как я могу это сделать?

это, вероятно, можно сделать даже со стандартным прологом, но так как я плохо понимаю логическое программирование, я не могу об этом подумать

спасибо: D


person ndp    schedule 08.04.2011    source источник
comment
Следует ли выполнять перестановки таким образом, чтобы не дублировать решения, которые включают в себя одинаковые элементы, появляющиеся в том же месте, что и для другого решения? Это первое, о чем мне пришло в голову поволноваться. Избегание повторов в последовательности решения кажется довольно простой модификацией обычного предиката перестановки.   -  person hardmath    schedule 10.04.2011


Ответы (3)


Вы можете построить такие перестановки, просматривая список.

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).

Этот код при возврате выдаст все допустимые перестановки. Я оставлю вам в качестве упражнения способ отбросить повторяющиеся перестановки.

person gusbro    schedule 08.04.2011
comment
Я неправильно прочитал требования OP. +1 к вам, и я выложил новую альтернативу на основе dif/2. - person Fred Foo; 15.04.2011

Вы можете сделать это довольно быстро с помощью 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 является стандартным Прологом, но в основных реализациях он есть.

person Fred Foo    schedule 15.04.2011

Мы определяем my_perm/2 на основе same_length/2, < a href = "https://stackoverflow.com/a/33212200/4609915"> list_permuted/2, dif и 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).

Вот пример запроса 1,2, предоставленный OP.

Мы используем call_time/2 для измерения времени выполнения в миллисекундах T_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: Последовательности ответов, выдаваемые процессором Пролога, были адаптированы для удобства чтения.

person repeat    schedule 19.10.2015
comment
goal_rt/2 не гнездится. Пожалуйста, сделай так. - person false; 19.10.2015