fregimus: (q)
[personal profile] fregimus
У меня возникла комбинаторная задачка со стековой машиной, которую было бы интересно проанализировать.

Представьте себе игру с перекладыванием карточек, целью которой является переставить карточки с буквами из исходного порядка в заданный. На каждой карточке написана или буква алфавита, или стрелка ↑. Правила перестановки букв таковы. Первоначально карточки с буквами и стрелкой выложены в ряд и берутся по одной слева направо. Если на карточке буква, то карточка кладется в стопку (если стопка пуста, то карточка будет в ней единственной, а если там уже есть карточки, то очередная карточка кладется поверх предыдущих). Если же на карточке стрелка, то эта карточка выбрасывается, а верхняя карточка из стопки выкладывается в отдельную строку для результата. Рассмотрим пример. Пусть задана последовательность карточек

О Р ↑ ↑ К ↑

Берем карточки слева направо по одной. Карточка О кладется в стопку, Р поверх нее. Затем первая стрелка велит выложить верхнюю карточку Р на выход, а вторая выкладывает (теперь верхнюю) О. Затем К кладется в стопку и следом, по команде последней стрелки, выкладывается на выход за первыми двумя. В результате получаем на выходе

Р О К

Вопрос задачи состоит в следующем. Пусть нам даны исходная строка (в нашем примере это ОРК) и предположительная выходная (РОК). Можно ли так разложить карточки-команды со стрелкой между буквами исходной строки, чтобы на выходе получилась заданная? Буквы в строке не обязательно все различные, например, А Н А Н А С — допустимая строка.

Можете легко проверить, что из строки А Б В можно получить только 5 из 6 возможных перестановок, а перестановку В А Б получить невозможно.

А ↑ Б ↑ В ↑ → А Б В
А ↑ Б В ↑ ↑ → А В Б
А Б ↑ ↑ В ↑ → Б А В
А Б ↑ В ↑ ↑ → Б В А
А Б В ↑ ↑ ↑ → В Б А

Предпочтительно конструктивное решение (т. е. правило расстановки), и, конечно, самое простое. Существует очевидное решение «в лоб»: будем расставлять n стрелок, где n длина строки, в любом возможном порядке, и проверять, получится ли на выходе искомая строка. Но нам придется перебрать n! возможных комбинаций — громадное число даже для 10 букв, так что такое решение не годится. Есть очень простое линейное в n решение для строки с различающимися буквами, но оно не работает, если разрешить повторы одинаковых букв в строке. А дальше ваш ход.

Доб. Наврал я с линейным решением — нашел контрпример.
Tags:

(no subject)

2011-10-29 02:59 (UTC)
Posted by [identity profile] slobin.livejournal.com
Пытаюсь понять, похож ли ваш алгоритм на мой, если его применять слева направо: у меня всё крутится вокруг ПЕРВОЙ буквы исходной строки. Идея такая: если первая буква попала на k-тое место в выходной строке, значит, к этому моменту из стека ушло ровно k букв, и он в этот момент стал пустым. Значит, попало в него тоже ровно k букв (и все они ушли). Значит, левее k находится "правильная" перестановка 2..k первых букв, а правее -- k+1..n последних. Правильность для наглядности проверяем рекурсивно, но там суммарное количество вызовов получается n, а накладные затраты на рекурсию можно, кажется, убрать изощрённым программированием (но я поленился). А если есть несколько разных кандидатов на позицию, куда попала первая буква, то вот тут-то перебор и взлетает.

Реализация этой идеи в виде кода здесь (питон и генераторы (генераторы ведь нужны, чтобы варианты генерировать, правильно? :-)). Собственно решение задачи -- функция (генератор) transform, а evaluate -- это просто такой юнит тест, она собственно применяет все эти стрелочки и выдаёт итоговую перестановку (всегда одну и ту же, искомую). Важно: то, что генерятся правильные перестановки, я проверяю тупо и в лоб, там ошибиться вроде негде, а вот то, что генерятся ВСЕ правильные, что этот алгоритм ничего не пропускает -- не проверяю вообще. Если я лажанулся, то здесь. Выдача на тестовом примере:

abr!a!!!cadab!!r!!!!a! (True, 'rababardaca')
abr!a!!ca!dab!!r!!a!!! (True, 'rababardaca')
abr!a!!cada!b!ra!!!!!! (True, 'rababardaca')

... Глупое, злое и одноразовое ...

(no subject)

2011-10-29 04:22 (UTC)
Posted by [identity profile] fregimus.livejournal.com
Спасибо, я посмотрю завтра или в воскресенье. Сегодня много дел.

Profile

fregimus: (Default)
fregimus

March 2014

S M T W T F S
       1
2 3456 78
910 1112 131415
16171819202122
23242526272829
3031     

Most Popular Tags

Page generated 2025-12-24 16:51

Expand Cut Tags

No cut tags