- •По дисциплине «Теория алгоритмов»
- •Глава 1. Машина Тьюринга
- •1. Теоретические сведения
- •1.1 Краткое описание машины Тьюринга
- •Глава 1. Машина Тьюринга 4
- •1. Теоретические сведения 4
- •2. Практическая часть: Примеры на составление программ для мт 9
- •Глава 2. Нормальные алгоритмы Маркова 31
- •1. Теоретические сведения 31
- •2.Практическая часть: Примеры на составление нам 34
- •Глава 3. Задачи теоретического характера 57
- •Глава 4. Машина Поста. 72
- •1.2 Программа для машины Тьюринга
- •1.3 Правила выполнения программы
- •1.4 Соглашения для сокращения записи
- •2. Практическая часть: Примеры на составление программ для мт
- •Практическая работа №1: Перемещение автомата, замена символов, анализ символов.
- •Задачи для решения
- •Практическая работа №2 Сравнение символов, стирание слова, удаление символа из слова.
- •Задачи для решения
- •Практическая работа №3: Сжатие слова, вставка символа в слово.
- •Задачи для решения
- •Практическая работа № 4: Раздвижка слова, формирование слова на новом месте, фиксирование места на ленте.
- •Задачи для решения
- •Глава 2. Нормальные алгоритмы Маркова
- •1. Теоретические сведения
- •1.1 Краткое описание нормальных алгоритмов Маркова
- •4. Если в левой части формулы подстановки указано пустое слово, то подстановка сводится, по определению, к приписыванию в слева к слову p:
- •1.2 Правила выполнения нам
- •2.Практическая часть: Примеры на составление нам
- •Практическая работа №5: Вставка и удаление символов, перестановка символов
- •Практическая работа №6: Использование спецзнака, фиксация спецзнаком заменяемого символа.
- •Практическая работа № 7: Перемещение спецзнака, смена спецзнака.
- •Практическая работа № 8: Перенос символа через слово, использование нескольких спецзнаков.
- •Глава 3. Задачи теоретического характера
- •Задачи для решения.
- •Практическая работа №10 Самоприменимость алгоритма
- •Задачи для решения.
- •Глава 4. Машина Поста.
- •Практическая работа №13. Работа с массивами
- •Практическая работа №14 Ориентация на ленте
- •Практическая работа 15. Действия над заданным на ленте множеством меток
- •Практическая работа 16. Сравнение
- •Простые программы
- •Литература
Практическая работа №6: Использование спецзнака, фиксация спецзнаком заменяемого символа.
Пример 1 (использование спецзнака)
A={a,b}. Удалить из непустого слова Р его первый символ. Пустое слово не менять.
Решение.
Ясно, что удалив первый символ слова, надо тут же остановиться. Поэтому, казалось бы, задачу решает следующий НАМ:
Однако это неправильный алгоритм, в чём можно убедиться, применив его к слову bbaba:
Как видно, этот НАМ удалил не первый символ слова, а первое вхождение символа a, а это разные вещи. Данный алгоритм будет правильно работать, только если входное слово начинается с символа a. Ясно, что перестановка формул в этом НАМ не поможет, т.к. тогда он будет, напротив, неправильно работать на словах, начинающихся с a.
Что
делать? Надо как-то зафиксировать,
пометить первый символ слова, например,
поставив перед ним какой-либо знак,
скажем *, отличный от символов алфавита
слова. После этого уже можно с помощью
формул вида
заменить
этот знак и первый символ
слова
на пусто и остановиться:
А как поставить * перед первым символом? Это реализуется формулой а* с пустой левой частью, которая, по определению, приписывает свою правую часть слева к слову.
Итого, получаем следующий НАМ:
:
1 1 1 1
bbaa → *bbaba → **bbaba → ***bbaba → ...
Как видно, этот алгоритм постоянно приписывает слева звёздочки. Почему? Напомним, что формула постановки с пустой левой частью применима всегда, поэтому наша формула (1) будет работать бесконечно, блокируя доступ к остальным формулам. Отсюда вытекает очень важное правило: если в НАМ есть формула с пустой левой частью (ав), то её место - только в самом конце НАМ. Учтём это правило и перепишем наш НАМ:
Казалось бы, всё в порядке. Однако это не так: наш алгоритм зациклится на пустом входном слове, т.к. постоянно будет применяться формула (3), а согласно условию задачи на таком слове НАМ должен остановиться. В чём причина этой ошибки? Дело в том, что мы ввели знак * для того, чтобы пометить первый символ слова, а затем уничтожить * и этот символ. Но в пустом слове нет ни одного символа, поэтому формулы (1) и (2) ни разу не сработают и постоянно будет выполняться формула (3). Следовательно, чтобы учесть случай пустого входного слова, надо после формул (1) и (2) записать ещё одну формулу, которая уничтожает «одинокую» звёздочку и останавливает алгоритм:
Вот теперь мы, наконец-то, составили правильный алгоритм.
Прежде чем перейти к следующим задачам, обобщим тот приём со звёздочкой, который мы использовали в примере 1.
Пусть в обрабатываемое слово Р входит несколько раз подслово а :
и нам надо заменить одно из вхождений α на подслово β. Такая замена делается с помощью формулы α→β. Однако, если мы применим эту формулу к слову Р, то будет заменено первое вхождение α. А что делать, если надо заменить какое- другое вхождение α , скажем второе или последнее? Так вот, чтобы на β заменялось не первое вхождение α , а какое-то другое, это другое вхождение надо как-то выделить, пометить, для чего следует рядом с ним (слева или справа) поставить некоторый символ, скажем *, отличный от всех других символов, входящих в P:
Такой символ будем в дальнейшем называть спецзнаком. Его роль - выделить нужное вхождение α среди других, сделать его уникальным. Поскольку только около этого вхождения есть спецзнак, то надо использовать формулу * α→β, чтобы заменить на β именно это вхождение α , а не какое-то другое.
Этот приём со спецзнаком следует запомнить, т.к. в НАМ он используется очень часто.
Правда, остаётся ещё одна проблема: как спецзнак разместить рядом с нужным вхождением а ? Следующие примеры показывают, как это делается.
Пример 2 (фиксация спецзнаком заменяемого символа)
А={0,1,2,3}. Пусть Р - непустое слово. Трактуя его как запись неотрицательного целого числа в четверичной системе счисления, требуется получить запись этого же числа, но в двоичной системе.
Например: 0123 → 00011011
Решение.
Как известно, для перевода числа из четверичной системы в двоичную надо каждую четверичную цифру заменить на пару соответствующих ей двоичных цифр: 0→ 00, 1 → 01, 2→ 10, 3→ 11. Такая замена, казалось бы, реализуется следующим НАМ:
Но этот алгоритм неправильный, в чём можно убедиться на входном слове 0123:
Ошибка здесь в том, что после замены четверичной цифры на пару двоичных цифр уже никак нельзя отличить двоичные цифры от четверичных, поэтому наш НАМ начинает заменять и двоичные цифры. Значит, надо как-то отделить ту часть числа, в которой уже была произведена замена, от той части, где замены ещё не было. Для этого предлагается пометить слева спецзнаком * ту четверичную цифру, которая сейчас должна быть заменена на пару соответствующих двоичных цифр, а после того как такая замена будет выполнена, спецзнак нужно поместить перед следующей четверичной цифрой:
Как видно, слева от спецзнака всегда находится та часть числа, которая уже переведена в двоичный вид, а справа - часть, которую ещё предстоит заменить. Поэтому никакой путаницы между четверичными и двоичными цифрами уже не будет.
Итак, спецзнак * сначала должен быть размещён слева от первой цифры четверичного числа, а затем он должен «перепрыгивать» через очередную четверичную цифру, оставляя слева от себя соответствующие ей двоичные цифры. В конце же, когда справа от * уже не окажется никакой цифры, спецзнак надо уничтожить и остановиться. Как приписать * слева к входному слову и как уничтожить спецзнак с остановом, мы уже знаем по предыдущему примеру, а вот «перепрыгивание» звёздочки реализуется с помощью формул вида *α→ βγ*, где α - четверичная цифра, а βγ - соответствующая ей пара двоичных цифр.
Итого, получаем следующий алгоритм перевода чисел из четверичной системы в двоичную:
Проверим этот НАМ на входном слове 0123:
Задачи для решения
Замечания:
В задачах рассматриваются только целые неотрицательные числа, если не сказано иное.
Под «единичной» системой счисления понимается запись неотрицательного целого числа с помощью палочек - должно быть выписано столько палочек, какова величина числа; например: 2→ | | , 5 → | | | | | , 0 → <пустое слово>.
A={a,b,c}. Из слова P удалить второй символ, если такой есть.
A={a,b,c}. Если в слове P не менее двух символов, то переставить два первых символа.
A={0,1,2}. Считая непустое слово P записью троичного числа, удалить из этой записи все незначащие нули.
A={a,b,c}. Приписать слово abc справа к слову P.
A={a,b,c}. Удалить из непустого слова P его последний символ.
A={0,1}. Считая непустое слово P записью числа в двоичной системе, получить двоичное число, равное учетверённому числу P (например: 101 ^ 10100).
A={0,1}. Считая непустое слово P записью числа в двоичной системе, получить двоичное число, равное неполному частному от деления числа P на 2 (например: 1011 ^ 101).
A={a,b}. В слове P все символы a заменить на b, а все (прежние) символы b - на a.
A={a,b,c}. Удвоить каждый символ в слове P (например: bacb a bbaaccbb).
A={a,b}. Приписать справа к слову P столько палочек, сколько всего символов входит в P (например: babb a babb ||||).
A={a,b}. Пусть слово P имеет чётную длину (0, 2, 4, ...). Удалить правую половину этого слова. (Рекомендация: использовать решение предыдущей задачи.)
A={a,b}. Пусть длина слова P кратна 3. Удалить правую треть этого слова.
A={a,b}. Приписать справа к слову P столько палочек, со скольких подряд идущих символов a начинается это слово (например: aababa a aababa\ | ).
A={a,b,c}. Удалить из слова P второе вхождение символа a, если такое есть.
A={a,b,c}. Удалить из слова P третье вхождение символа a, если такое есть.
A={a,b,c}. Оставить в слове P только первое вхождение символа a, если такое есть.
