A+B:-findall(X,(append(X,Y,A),append(Y,X,A)),[_|Z]),length(Z,B).
Wypróbuj online!
Definiuje predykat, +/2
który jako pierwszy argument przyjmuje ciąg (w postaci listy kodów znaków A
) i ustawia drugi argument (B
) na kolejności symetrycznej rotacji najwyższego rzędu.
Wyjaśnienie
Ten program wykorzystuje fakt, że zbiór symetrycznych obrotów na sznurku jest grupą cykliczną, a zatem rząd zbioru symetrycznych rotacji jest równy rzędowi symetrycznego obrotu najwyższego rzędu. W ten sposób program jest w stanie obliczyć pożądany wynik, znajdując całkowitą liczbę symetrycznych obrotów na ciągu wejściowym.
Objaśnienie kodu
Większość ciężkich operacji podnoszenia odbywa się przez wezwanie do findall/3
orzeczenia. findall/3
Orzeczenie wyszukuje wszystkie inne możliwe wartości pierwszego argumentu ( X
w tym przypadku) w taki sposób, że ekspresja podano jako drugi argument jest prawdą ( (append(X,Y,A),append(Y,X,A))
bardziej na później). Na koniec przechowuje każdą z tych możliwych wartości X
jako listę w końcowym argumencie ( [_|Z]
).
Wyrażenie przekazane findall/3
jako drugi argument (append(X,Y,A),append(Y,X,A))
używa append/3
predykatu do określenia, że X
konkatenacja z niektórymi jeszcze niezdefiniowanymi Y
musi być równa A
łańcuchowi wejściowemu i że to samo Y
konkatenowane z X
musi również być równe A
. Oznacza to, że X
musi to być jakiś prefiks, A
tak że jeśli zostanie usunięty z przodu A
i dodany z tyłu, powstały ciąg będzie taki sam jak A
. Zbiór X
s o tej właściwości ma prawie jeden do jednego związek z symetrycznymi obrotami A
. Zawsze występuje dokładnie jeden przypadek podwójnego liczenia, który jest spowodowany faktem, że zarówno pusty ciąg znaków, jak i A
przedrostkiA
które odpowiadają obrotowi 0 z A
. Ponieważ 0
obrót A
jest zawsze symetryczny, długość wynikowej listy X
s od findall/3
będzie o jeden większa niż liczba symetrycznych obrotów na A
.
Aby rozwiązać problem podwójnego liczenia, używam dopasowania wzorca do trzeciego argumentu findall/3
predykatu. W listach prologów są reprezentowane jako pary głowy (pierwszy element) i ogona (reszta). Zatem [_|Z]
reprezentuje listę, której ogon jest równy, jest równy Z
. Oznacza to, że długość Z
jest o jeden mniejsza niż liczba przedrostków znalezionych w findall/3
predykacie, a zatem równa liczbie obrotów symetrycznych A
. Na koniec używam length/2
predykatu, aby ustawić B
długość Z
.