A+B:-findall(X,(append(X,Y,A),append(Y,X,A)),[_|Z]),length(Z,B).
Спробуйте в Інтернеті!
Визначає предикат, +/2
який приймає рядок (у вигляді списку кодів символів) як свій перший аргумент ( A
) і встановлює свій другий аргумент ( B
) у порядку симетричного обертання вищого порядку.
Пояснення
Ця програма використовує той факт, що безліч симетричних обертів на рядку є циклічною групою, і тому порядок набору симетричних обертів дорівнює порядку симетричного обертання вищого порядку. Таким чином програма здатна обчислити бажаний результат, знайшовши загальну кількість симетричних обертів на вхідній рядку.
Пояснення коду
Більшість важких підйомів здійснюється за викликом до findall/3
присудка. findall/3
Предикат знаходить все різні можливі значення для першого аргументу ( X
в даному випадку) , так що вираз , наведене в якості другого аргументу є істинним ( (append(X,Y,A),append(Y,X,A))
, про це пізніше). Нарешті, воно зберігає кожне з цих можливих значень X
як список у заключному аргументі ( [_|Z]
).
Вираз, переданий findall/3
як другий рухомий фрагмент, (append(X,Y,A),append(Y,X,A))
використовує append/3
присудок, щоб вказати, що X
об'єднане з деяким ще не визначеним Y
рівнем має бути A
вхідним рядком, а також те, що Y
з'єднане з цим X
також повинно бути рівним A
. Це означає, що X
повинен бути якийсь такий префікс A
, що якщо його вилучити з передньої частини A
та додати до задньої частини, то результуюча рядок буде такою самою, як A
. Множина X
s з цією властивістю майже має однозначну відповідність симетричним обертанням A
. Завжди рівно один випадок подвійного підрахунку, який викликаний тим, що як порожній рядок, так і A
префіксиA
які відповідають 0-обертанню A
. Оскільки 0
-обертання A
завжди симетричне, довжина результуючого списку X
s від findall/3
буде на один більша, ніж кількість симетричних обертань на A
.
Для вирішення задачі подвійного підрахунку я використовую відповідність шаблону на третьому аргументі findall/3
присудка. У списках Пролога представлені у вигляді пар голови (перший елемент) та хвоста (решта). Таким чином, [_|Z]
представлений список, хвіст якого дорівнює, дорівнює Z
. Це означає, що довжина на Z
один менше кількості префіксів, знайдених findall/3
присудком і, таким чином, дорівнює кількості симетричних обертів A
. Нарешті, я використовую length/2
присудок, щоб встановити B
довжину Z
.