/
Теги: математика
Текст
С. А. АБРАМОВ
МАТЕМАТИЧЕСКИЕ
ПОСТРОЕНИЯ
И ПРОГРАММИРОВАНИЕ
Под редакцией
С. С. ЛАВРОВА
МОСКВА «НАУКА»
ГЛАВНАЯ РЕДАКЦИЯ
ФИЗИКО-МАТЕМАТИЧЕСКОЙ ЛИТЕРАТУРЫ
1978
518
А 16
УДК 519.95
Математические построения и программирование.
С. А. Абрамов. Главная редакция
физико-математической литературы изд-ва «Наука», М., 1978.
В книге программирование рассматривается как
дисциплина, имеющая дело с задачами на построение
математических объектов. Построение проводится на
базе некоторого фиксированного набора элементарных
операций. Внимание читателя сосредоточивается на
алгоритмической стороне математических задач.
Имеется большое количество примеров и задач для
самостоятельного решения.
Книга рассчитана на школьников старших
классов, студентов техникумов и втузов.
20204—071
0бЗ(02)-78 72'78
© Главная редакция
физико-математической литературы
издательства «Наука», 1978
ОГЛАВЛЕНИЕ
Предисловие 4
Введение ... s , . , . , Б
Глава I. Построения и алгоритмы 7
§ 1. Примеры задач на построение. Данные, операции 7
§ 2. Логический анализ ситуации 15
§ 3. Запись алгоритмов, которые содержат проверки . . 21
§ 4. Различные наборы операций 26
§ 5. Избыточность набора операций . . 34
Г л а в а II. Цикл . . . , 39
§ 1. Ограниченность поля зрения 39
§ 2. Логические выражения 46
§ 3. Повторение действий , , . . . 53
§ 4. Массивы . . ..,»**. 58
§ 5. Алгоритм Евклида . . , » , , 62
Глава III. Рекурсия 70
§ 1. Упрощение исходных данных 70
§ 2. Рекуррентные соотношения 75
§ 3. Анализ рекурсивных алгоритмов 82
§ 4. Как выполнять рекурсивные алгоритмы , . . , 89
§ 5. Пример избавления от рекурсий . . , ... ., а . . * 95
Глава IV. Поиск . . , «,,.... 104
§ 1. Справочник и поиск сведений в нем 104
§ 2. Подмножества конечных множеств 113
§ 3. Бектрекинг , . 120
§ 4. Восемь ферзей и лабиринт , 126
§ 5. Графы и деревья . , 135
Глава V. Дальнейшие рассмотрения 147
§ 1. Подстановки 147
§ 2. Вычисление а" 156
§ 3. Алгоритмы с логарифмической трудоемкостью , , . 164
Дополнение I. Переходы 173
Дополнение II. Об одном полезном качестве рекурсии 178
Заключение . , ,..,,,,»,,,,,,»,**», 187
8
ПРЕДИСЛОВИЕ
Эта книга — не учебник программирования. Здесь совершенно
отсутствуют как сведения о современных вычислительных машинах,
так И' инструкции по составлению программ для этих машин. Пред'
мет книги — разнообразные темы, обсуждение которых будет
способствовать развитию алгоритмической интуиции читателя и даст
представление о характерных приемах решения алгоритмических
задач.
Каждый старшеклассник уже обладает минимальными
алгоритмическими навыками. Например, геометрические задачи на
построение — хорошая основа для приобретения таких навыков. Эта
школьная тема — одна из наиболее «алгоритмических» и, в частности,
близких программированию. Поэтому изложение материала
начинается с разбора геометрических задач.
Программирование может рассматриваться как
математическая дисциплина, имеющая дело с задачами на построение
математических объектов (не обязательно геометрических). Построение
проводится на базе фиксированного набора элементарных операций.
Одна из специфических сторон деятельности программиста — поиск
по возможности более экономного решения. Этому вопросу в книге
уделяется изрядное внимание.
Автор надеется, что в книге найдет для себя нечто полезное
и тот читатель, который уже приобрел начальный
программистский опыт. Скорее всего, такому читателю будут интересны
последние две главы.
Автор с удовольствием выражает свою признательность
Святославу Сергеевичу Лаврову за множество ценных советов и бесед при
подготовке рукописи книги.
С. А. Абрамов
ВВЕДЕНИЕ
Для решения геометрических задач на построение
с помощью циркуля и линейки требуется указать способ
построения необходимых объектов. Это не то же самое,
что выполнить фактическое построение для некоторых
конкретных данных, на самом деле нужно учесть и
охватить все возможности взаимного расположения исходных
точек, прямых, окружностей и т. д.
Подобного рода задачи известны и из алгебры:
решение систем линейных уравнений (скажем, второго и
третьего порядков) с помощью четырех основных
арифметических операций; решение квадратного уравнения
с помощью тех же операций и операции извлечения
корня и т. д. Правда, в алгебре обычно говорят не о
построении, а о вычислении, но это не меняет сути дела.
И в тех, и в других задачах задается множество
объектов — геометрических фигур определенного вида или
чисел, указываются операции, с помощью которых из
данных объектов можно получать новые, и требуется
указать способ построения объекта (совокупности
объектов), удовлетворяющего некоторому условию.
Мы будем заниматься задачами именно такого
характера. Кроме геометрических и алгебраических задач,
будут и другие — их условно можно назвать
логическими. Каждый раз мы будем предлагать некоторый
способ построения. Будут вырабатываться принципы оценки
качества способов построения. Различные способы будут
сравниваться на основе этих принципов.
5
Интерес к подобным задачам в настоящее время
достаточно велик ввиду широкого использования
вычислительных машин в самых разных научных исследованиях
и технике. Вычислительная машина — это специальный
автомат, который совершает некоторые математические
построения (в частности, вычисления) в точном
соответствии с указанным способом построения. Для способов
построения в этой книге вводится специальная форма
записи.
ГлаваГ. ПОСТРОЕНИЯ И АЛГОРИТМЫ
В этой главе рассматриваются задачи на построение
из разных областей математики. В каждом случае
фиксируется множество объектов: Этому множеству должны
принадлежать исходные данные, окончательные
результаты и все промежуточные элементы построения.
Фиксируется набор операций, которые можно производить
над уже имеющимися объектами для получения новых.
Принимаются некоторые соглашения, касающиеся формы
записи способов построения (алгоритмов).
§ 1. Примеры задач на построение. Данные, операции
1. Построения с помощью циркуля и линейки. Все
построения ведутся в некоторой фиксированной
плоскости. Исходные данные образуют конечную совокупность
объектов — прямых линий, окружностей и точек. Другие
объекты элементарной геометрии задаются с помощью
прямых, окружностей и точек. Например, отрезок
задается двумя точками (концами), дуга — тремя точками
окружности и т. д. Допустимые операции — проведение
прямых и окружностей, выделение точек касания и
пересечения. Более точно: к данной с самого начала
совокупности прямых, окружностей и точек подключаются
новые элементы, возникающие как результаты выполнения
следующих допустимых операций:
Г проведение прямой через две имеющиеся точки;
2° проведение окружности с центром в одной из
имеющихся точек с радиусом, равным расстоянию между
двумя имеющимися точками;
3° выделение точки, являющейся общей для двух
несовпадающих окружностей или прямой и окружности
(т. е. точкой пересечения или касания). Прямые и
7
окружности, о которых идет речь, выбираются из числа
данных или уже построенных прямых и окружностей,
имеющих общую точку.
Описание хода построения должно быть
сопровождено объяснением, какие из элементов построенной
совокупности образуют искомую фигуру.
Рассмотрим задачу деления отрезка, соединяющего
точки а и Ь, на две равные части. Опишем шаги
построения. На* рис. 1 рядом с обозначением прямой, окружности
Рис. 1.
или точки в скобках указан номер шага, на котором
построен объект.
Ш а г 1: построить прямую, проходящую через а и Ь,
обозначить ее L;
Ш а г 2: построить окружность с центром в а и с
радиусом, равным расстоянию от а до Ь, обозначить ее
А;
Ш а г 3: построить окружность с центром в b и с
радиусом, равным расстоянию от b до а, обозначить ее В;
-Шаг 4: выделить точку, общую А и В, обозначить
ее г;
Ш а г 5: выделить точку, общую А и В, отличную
от г, обозначить ее s;
III а г 6: построить прямую, проходящую через г и s,
обозначить ее М;
Ш а г 7: выделить точку, общую прямым М и L,
обозначить ее q
Точка q — искомая.
8
Задача I. Каковы шаги построения окружности, описанной
вокруг данного треугольника? Предполагать, что треугольник
задан своими вершинами.
Удобно иметь дело только с одним видом объекта —
с точкой плоскости. Прямая задается двумя точками, а
окружн°сть — тремя
точками: первая
точка — это центр,
расстояние же между
второй и третьей
точками дает радиус.
Условимся об
обозначениях операций
выделения точек:
Г Л (р, q\ r, s) —
точка пересечения
прямых, заданных
точками р, q и г, s;
2° П (р, q; r, s, t) — точка пересечения или
касания прямой, заданной точками р, q, и окружности,
заданной точками г, s, t;
3° Г) (р, q, r, s, t, и) — точка пересечения или
касания окружностей, заданных точками р, q, r и s, t, и.
Необходимо
условиться, какая из двух
точек пересечения
является результатом
операции 2° или операции
3°. Для этого на
прямой, проходящей через
р и q, зададим
направление от р к q. Будем
считать, что операция 2°
Рис. 3. выбирает из двух точек
пересечения прямой с
окружностью ту, которая предшествует другой (рис.
2).Результатом операции 3° будет та точка пересечения двух
окружностей, которая находится левее, если смотреть
из центра р в направлении центра s (рис. 3). Если прямая
и окружность или две окружности касаются друг друга,
то во всех случаях обсуждаемые операции дают одну и
ту же точку. Мы будем допускать случай, когда
окружность вырождается в точку, т. е. радиус задан двумя
совпадающими точками.
9
Задача 2. Показать, что отрезок с концами Л («• Ъ\ а, с, d)
и Ъ — сумма отрезков с концами а, Ь и с, d. Если отрезок с концами
а, Ь больше отрезка с концами с, d, то разность этих отрезков —*
отрезок с концами П (Ь, а; а, с, d) и Ь.
2. Вычисления с помощью арифметических операций.
В качестве исходных данных рассмотрим конечную
совокупность чисел. Допустимыми операциями будем
считать:
Г вычисление суммы двух чисел,
2° вычисление произведения двух чисел.
Результат операции получает обозначение и
включается в совокупность рассматриваемых чисел.
Пусть дано х, и нужно вычислить 4л:2+3л;—2.
Возведение в степень и вычитание не входят в данный набор
операций, поэтому переходим к выражению
4хдс+ах+(—-2).
Теперь можно выписать шаги:
Ш а г 1: вычислить значение хх, обозначить его у;
Ш а г 2: вычислить значение Ау, обозначить его г;
Ш а г 3: вычислить значение Зх, обозначить его и}
Ш а г 4: вычислить значение z+u, обозначить его v;
Ш а г 5: вычислить значение v+(—2), обозначить
его w
Значение w — искомое.
В первом, геометрическом, примере предложенный
способ построения обеспечивал построение середины для
любого отрезка на плоскости, и здесь, каким бы ни было
значение х, выполнение выписанных пяти шагов даст
значение w~4xiJr3x—2. Если х~0, то w——2, если
х=\, то ау=5 и т. д. Вспомогательные величины у, г, и,
v к концу вычислений будут иметь значения хг, 4х2, Зх,
4x2+3x.
Все, что вычисляется в результате выполнения
некоторой последовательности операций 1° и 2°,— это
значения многочленов, т. е. сумм одночленов ax'yk. . .zl,
где х, (/,..., 2 — исходные данные и i, k, . . ., I —
неотрицательные целые числа. В самом деле, операции
можно выполнить не над конкретными числовыми
значениями х, у, . . ., z, а над буквами х, у, . . ., г, проводя
не арифметические вычисления, а алгебраические
выкладки. Сумма и произведение любых двух
многочленов — это снова многочлен, откуда и следует
утверждение.
10
Разбиением на несколько слагаемых, вынесением
множителей за скобки и раскрытием скобок можно
представлять данное выражение в разных видах. Один вид
представления оказывается более удобным для организации
вычислений, чем другой. Значение трехчлена 4#2+3x—2
удобно вычислять, предварительно преобразовав
трехчлен в х(4х+3)—2. Так потребуется выполнение двух
умножений, а описанный выше способ требует три
умножения. Число сложений в обоих случаях — два.
Задача 3. Описать шаги вычисления значения 2х*—Здс3—|—
+4х2—5*+6 по данному х (здесь можно обойтись 4 умножениями
и 4 сложениями).
Задача 4. Описать шаги вычисления значения Зх2у2—2ху2—
—7х2у—Ау*-\-\Ъху-\-2хг—Здс+10(/+6 по данным х, у (здесь можно
обойтись 8 умножениями и 8 сложениями).
3. Перестановка букв. Наряду с известной
комбинаторной задачей подсчета числа перестановок п
предметов, представляет интерес и задача явного
перечисления всех перестановок. В обеих задачах несущественно,
какие именно предметы имеются в виду, их можно
заменить некоторыми символами. Это позволяет
интерпретировать многие комбинаторные задачи следующим образом.
Пусть V — некоторое конечное множество различных
символов. Нужно выяснить, сколько существует
конечных последовательностей символов из V, обладающих
какими-либо оговоренными в задаче свойствами.
Например, задача о перестановках требует подсчитать
количество последовательностей, каждая из которых содержит
все символы из V по одному разу. Задача о перечислении
всех перестановок — это задача построения всех таких
последовательностей символов.
Далее каждый символ из V будет называться буквой,
а данное множество букв V — алфавитом. Например,
буквами могут служить А, 6, О, f. Алфавитами могут
быть
U = {A, Б, В, Г, Д, Е, Ж, 3, И, К, Л, М, Н, О,
П, Р, С, Т, У, Ф, X, Ц, Ч, Ш,Щ, Ь, Ы, Ъ,
Э, Ю, Я},
V ={0, 1, 2, 3, 4, 5, 6, 7, 8,9},
W = {!,♦}.
Конечная последовательность букв некоторого
алфавита будет называться словом в этом алфавите или
просто словом, если это не вызывает недоразумений.
11
Например, 012013 —слово в алфавите V, t^ttOttt —
слово в алфавите W и ЯЮЭ — слово в
алфавите U.
Каждая буква алфавита является словом в этом
алфавите. Другой важный частный случай слова —
это пустое слово. Пустое слово не содержит ни одной
буквы.
Два слова считаются равными, если они состоят из
одинакового числа букв и на соответствующих местах
стоят одни и те же буквы.
Здесь и в следующих параграфах мы будем решать
задачи построения слов.
Рассмотрим следующие допустимые операции над
словами:
Г пусть т — непустое слово, тогда еолова(т) —
это первая буква слова т;
2° пусть т — непустое слово, тогда хвост(т) —
это слово, которое получается из т отбрасыванием
первой буквы;
3° пусть т, I, k, . . .— любые слова в некотором
количестве, тогда °(/n, /, k, . . .) — это слово,
получающееся приписыванием слов т, I, k, . . . друг к другу в
указанном порядке.
Операции Г, 2° служат для разборки слова на
составные части. Операция 3°— операция сцепления, служит
для сборки слова.
Применяя эти тр,и операции, решим следующую
задачу на построение. Дано слово т,т состоящее из трех
различных букв некоторого алфавита. Построить все
слова, которые получаются из исходного
всевозможными перестановками букв. Мы воспользуемся самым
простым путем: разберем слово на буквы, дадим им
обозначения (х, у, г) и будем составлять различные
комбинации букв.
Ш а г 1: построить слово голова(т), обозначить его х;
Ш а г 2; построить слово хвост(т), обозначить его I;
Ш а г 3: построить слово голова(1), обозначить его у;
Ш а г 4: построить слово хвост(1), обозначить его г;
Ш а г 5: построить слово ^(х, z, у), обозначить его а;
Ш а г 6: построить слово^(у, х, г), обозначить его Ы
Ш а г 7: построить слово w(y, г, х), обозначить его с;
Ш а г 8: построить слово и(г, х, у), обозначить его di
Ш а г 9: построить слово u(z, у, х), обозначить его t
Слова т, а, Ь, с, d, e — искомые.
12
Задача 5. Рассмотрим операции перестановки первой и
второй букв и перестановки второй и третьей букв в слове. Обозначим
первую ПВ (т), вторую— ВТ (т), где т — слово. Решить
разобранную выше задачу, пользуясь только этими операциями.
* * *
Мы рассмотрели описания способов построения
различных математических объектов. В этих описаниях легко
увидеть общие черты. Описания -способов распадаются
на описания шагов. На каждом шаге осуществляется
построение с помощью одной операции. За результатом
операции закрепляется обозначение для того, чтобы этот
результат мог быть использован на следующих шагах.
Описания шагов у нас заканчивались словами
«обозначить его (ее) . . .». Можно условиться о кратком
описании шагов. Шаг 9 в последнем примере можно описать
е: = и(г, у, х). Такая запись читается, как прежде:
построить слово "(г, у, х), обозначить его е. Знак : =ь=»
похож на знак равенства = , но отличается от него и
видом, и смыслом: знак = изображает отношение равенства
между двумя объектами, знак :=изображает приказ —
выполнить некоторую операцию и присвоить результату
указанное обозначение.
Конструкции вида е:= "(z, у, х) будем называть
приказами присваивания.
Когда это будет удобно, мы будем использовать и
приказы присваивания вида р:=<7, а:=3 и т. д., т. е.
помещать справа от знака : = известную величину,
которая не нуждается в построении. Примеры, когда такие
приказы оказываются удобными, появятся позднее.
Для удобства обсуждения способов построения будем
давать им обозначения. Можно, например, способ
построения середины отрезка назвать С. Тогда вместо
Шаг 1, Шаг 2, ... будем писать С\ , С2 ,. . .
Описанию шагов С\, С2, . . . предпошлем словесное описание
назначения способа. Здесь можно указать, что дано,
что нужно получить и какими операциями. Это
предварительное неформальное описание будет обозначено
просто С (без» номера).
Перепишем целиком способ построения:
С: Даны точки а и Ь. С помощью циркуля и линейки
построить точку q — середину отрезка, соединяющего
эти точки;
13
CI: r:= П (a, a, b; b, a, b);
C2: s:= П Ф, a, b; a, a, b);
C3: q:=r\ (a, b; r, s)
Вернемся к задаче вычисления значения трехчлена
4х2+3х—2. Воспользуемся равенством 4хг+3х—2=
=x(4x+3)—2.
Т: Дано число х. С помощью операций сложения и
умножения вычислить значение ш=4яа+3л;—2;
7Т. г/:=4х;
Т2: г:=г/+3;
ТЗ: t:=xz;
ТА: w:=t+(—2)
Перепишем и способ построения слов.
L: Дано слово т, состоящее из трех различных букв
некоторого алфавита. С помощью операций голова,
хвост, ^построить слова а, Ь, с, d, e, которые
получаются из слова т перестановками его букв и
отличаются от него и друг от друга-
Ы: х:=голова(т)\
'L2: I: = хвост (т);
L3: у:=голова(1);
L4: г: = хвост (I);
L5: а:="(х, г, у)\
L6: Ь:=^{у, х, z)\
П: с:="(</, z, х)\
18: й:="{г, x, у);
L9: е: = "(г,у,х)
В арифметических задачах аргументом операции или,
как говорят, оперантом, может быть как обозначение
числа, так и явно указанное число. В задачах
построения слов тоже хотелось бы использовать в качестве опе-
рантов и обозначения слов, и сами слова. Возможна
путаница: если написано а, то не ясно, имеется ли в виду
слово, обозначенное буквой а, или само однобуквенное
слово а. Чтобы исключить возможность недоразумений,
мы будем в тех случаях, когда явно указывается слово,
заключать его в кавычки. Результат выполнения приказа
н: = и(т, «а») состоит в том, что буквой п будет
обозначено то, что получается из слова, обозначенного т
приписыванием буквы а. Если выполнится приказ п:—^(т,
а), то п будет обозначать слово, получающееся
сцеплением слов, обозначенных т и а. Если потребуется явно
выписать пустое слово, мы будем писать « ».
14
Способы построения (вычисления, нахождения)
будем называть алгоритмами построения (вычисления,
нахождения).
Задача 6. Описать алгоритм решения следующей задачи.
Даны два параллельных неравных отрезка. Пользуясь только
линейкой (т. е. операцией П. {а, Ъ; с, d)), построить середины этих
отрезков.
Задача 7. Описать алгоритм вычисления х* с помощью
операции умножения. (Можно обойтись двумя умножениями.
Сколько умножений потребуется для вычисления х10?)
Задача 8. Описать алгоритм решения следующей задачи.
Все слова, получающиеся перестановкой букв в данном
трехбуквенном слове, слить в одно слово, записав их в каком-нибудь порядке
одно за другим, разделяя буквой <>. Пользоваться операциями
голова, хвост, "->.
§ 2. Логический анализ ситуации
1. Кратчайший путь. В предыдущем параграфе мы
разобрали совсем простой геометрический алгоритм.
В более сложных задачах построения с помощью циркуля
и линейки приходится учитывать различные возможности
взаимного расположения данных объектов и в
зависимости от этого выбирать тот или иной путь решения.
Рассмотрим пример. На плоскости даны прямая L и две
различные точки А и В, из которых не более одной лежит на
прямой L. Построить на прямой точку С такую, что
расстояние |ЛС|+|ВС| — наименьшее из возможных.
Алгоритм построения включает в себя анализ:
расположены ли точки А и В по разные стороны от L? Если
да, то точка пересечения прямой, проходящей через А
и В, с прямой L — искомая. Если нет, то нужно отразить
точку В симметрично относительно С и получить таким
образом точку D. Затем построить точку пересечения
прямой, которая проходит через А и D, с прямой L
(рис. 4, 5).
Возможны и другие алгоритмы построения точки С, но
каждый из них включает проверку каких-то условий.
Не существует алгоритма, в котором использовались бы
только рассмотренные в § 1 операции.
Это утверждение можно доказать, привлекая аппарат
аналитической геометрии и дифференциального исчисления. Вот набросок
Доказательства.
Пусть для задачи, в которой заданы точки А, В, ... и нужно
построить точки Р, Q разработан алгоритм построения. Пусть
этот алгоритм представляет собой последовательность
рассмотренных в § 1 операций добавления новых точек. Если в плоскости ка-
15
ким-то образом ввести декартовы координаты, то исходные точки
изобразятся парами чисел (Alt А2), (В1г В2), • • •> точки, которые
будут построены при выполнении алгоритма,— парами чисел
(Pi, Ра)< (Qi> Q2). ••• Пусть исходная система точек зависит от
действительного числа t, т. е. имеются функции Ai(f), A2(t), B1(t), B2(l),
. . . Пусть для любого значения t точки (At(t), A2(t)), (B1(t), B2(t)),
. . . таковы, что возможны построения в соответствии с имеющимся
алгоритмом (т. е. окружности и прямые, точки пересечения или
касания которых надо построить, действительно пересекаются или
касаются, и точки, через которые проводятся прямые, не совпадают).
Система точек, которая будет построена, также зависит от t, т. е.
получаются функции Pi(t), P2(t), Qi(0. Qa(0. •••
«X
<?ч
♦
^
Рис. 4.
Рис. 5.
Лемма. Если Ax(f), A2(t), B1(/), B2(f), ...—
дифференцируемые бесконечное число раз функции, то P1(t), P2(t), Qx(t), Qs(0
. . .— тоже дифференцируемые бесконечное число раз функции.
Доказательство проводится для каждой операции добавления
точки в отдельности. Далее — индукция по числу шагов
алгоритма.
Пусть в нашей задаче отрезок АВ имеет угол наклона к прямой
L, равный л/4. Будем считать, что одна координатная ось совпадает
с L, причем начало отсчета — это проекция точки А, а единичная
точка — точка Е, являющаяся проекцией В. Вторая координатная
ось перпендикулярна прямой L, на ней выбран тот же масштаб и
задано направление, при котором ордината точки В больше
ординаты точки А (рис. 6). Пусть теперь отрезок АВ перемещается
параллельно самому себе так, что проекция его на ось абсцисс
остается неподвижной. Обозначим ординату точки А через /, тогда
координаты точки Л (0, t) и точки В(\, t-\-\) — дифференцируемые
бесконечное число раз функции. Исследуем зависимость от t
ординаты искомой точки С. Пусть /:>0, тогда точки А и В расположены
по одну сторону от L. Точка С может быть построена как точка
пересечения оси абсцисс с прямой, проходящей через точку А и
через точку D, симметричную точке В относительно оси абсцисс
16
(рис. 7). Спроецировав точку А на BD, получаем точку F. Из
подобия треугольников DCE и DAF получаем CElAF=DElDF. Так
как AF=1, DE=BE=t+\, DF=DE+EF=DE+t=2t+l, то СЕ=
<+1 _ 1 [/4
~2/+1
£>£,г /+1 „ .
= TrpAF=~1 , ,■ и абсцисса точки С есть 1-
£Лг 2/+1
Ж/2
Рис. 6.
Рис. 7.
Пусть теперь —1</<0. В этом случае абсцисса точки С есть
—t. Таким образом, абсцисса точки С представляет собой функцию
от /(рис. 8), которая не имеет производной при /=0. Это доказывает,
что общий алгоритм построения точки С, использующий только
операции, рассмотренные в § 1, не существует.
Задача 1. Доказать, что следующий алгоритм построения
точки С: «в трапеции, вершины которой суть точки А, В и
симметричные им относительно L, построить точку пересечения
диагоналей», требует анализа расположения точек относительно L.
Мы примем, что алгоритм построения может включать
в себя анализ взаимного расположения объектов на
плоскости.
17
Будем исходить из предположения, что для двух
множеств на плоскости, каждое из которых представляет
собой точку, прямую или окружность, мы умеем
устанавливать, имеют ли они хотя бы одну общую точку.
Кроме этого, будет возможность проверять, выполнено
ли отношение порядка между тремя точками, лежащими
на одной прямой, т. е. верно ли для трех попарно
различных точек А, В и С, лежащих на одной прямой, что В
находится между Л и С.
Набор операций, допустимых в построениях с
помощью циркуля и линейки, пополнился. О том, как
записывать алгоритмы, включающие операции проверки
условий, речь пойдет в следующем параграфе.
Примечание. Операции fl (я. Ь; с, d, e) и П (о, Ь, с; d,
е, f) включают в себя на самом деле некоторый логический анализ.
Этот анализ приводит к выбору одной из точек пересечения. Как
показано, этого анализа недостаточно для решения задачи
построения кратчайшего пути. Если бы с помощью этих операций к уже
имеющейся совокупности точек присоединялись обе точки
пересечения сразу, то, пользуясь ими и операцией Г) (в> Ь\ с, d), нельзя
было бы решить даже задачу построения суммы двух отрезков.
Традиционно в число операций, которые допускаются
в построениях с помощью циркуля и линейки, включается
еще и операция выбора «произвольной» точки в плоскости
или ее части, ограниченной прямыми, окружностями,
лучами, отрезками и дугами. Допускается, что эта часть
плоскости уходит в бесконечность. Все прямые и
окружности, лучи, отрезки и дуги которых ограничивают
часть плоскости, должны принадлежать к числу данных
или уже построенных прямых и окружностей, а концы
отрезков, лучей и дуг — к числу данных или уже
построенных точек. «Произвольная» точка выбирается вне
упомянутых отрезков, лучей и дуг.
Операция выбора «произвольной» точки неявно включает в
себя логический анализ — при этом выборе должны быть
удовлетворены все условия, которые определяют данную часть плоскости.
2. Вычисление абсолютной величины. В § 1 было
доказано, что все, что можно вычислять с помощью
операций сложения и умножения,— это значения
многочленов от данных величин. Если же, кроме сложения и
умножения, можно проверять истинность равенств и
неравенств между двумя значениями, то круг
вычислительных задач, для которых существует алгоритм решения,
18
расширяется. Например, если среди отношений, которые
можно проверять, есть отношение < (меньше), то ясно,
как вычислить \х\.
Теорема. Не существует многочлена f (х) = fax"-\-
-f- f„-i.xn~l+ ■ • • +/о такого, что для каждого числа х
выполнено f{x)~\x\.
Если речь идет о равенстве f(x)=\x\ на множестве всех
действительных чисел, то абсурдность его следует из того, что многочлен
всюду имеет производную, а \х\ не име.ет производной в 0. На самом
деле не существует даже такого многочлена f(x), что f(x)=\x\ на
множестве целых чисел.
Лемма. Пусть f(x) — многочлен степени nug(x)=
=gkxk~b~' • •+£<>—многочлен степени k^.n. Пусть /(1)=
=g(l). /(2)=g(2), . . ., f(n+l)=g(n+\). Тогда k=n
U /n=gfi> • • •> ft>~go-
Доказательство. Пусть для многочленов
f(x) ng(x) утверждение леммы не имеет места. Многочлен
){х)—g(x) имеет степень, не большую чем п. Однако он
имеет по крайней мере п+l корень: 1, -2, . . ., л+1. Это
противоречит теореме Безу.
Докажем теорему. Пусть f(x) — многочлен такой,
что f{x)—\x\ для любого целого значения х. Пусть п —
степень f(x). Ясно, что п^\. Для х=1, 2 п+1
имеет место равенство f(x)=x. Из леммы следует, что
многочлен f(x) совпадает с многочленом х. Но при х=—1
имеем \х\—\—1|=1, что не равно значению х. Теорема
доказана.
Замечание. В лемме на самом деле несущественно, что
значения многочленов совпадают именно при х=1, 2, . . ., п+1.
Можно вместо 1, 2 . . ., п+1 взять любой набор попарно различных
чисел, который состоит из п-\-\ элемента.
Задача 2. Доказать, что не существует многочлена f(x, у)
Для всех целых чисел х, у, равного наибольшему из х, у (т. е.
max (л;, у)). Указание, max (x, —х)=\х\.
3. Выбрасывание повторяющихся букв. Пусть дано
трехбуквенное слово в некотором алфавите, которое
может содержать повторяющиеся буквы. Требуется
построить слово, в которое каждая буква из первого слова
входит один раз.
Если круг допустимых операций ограничивается
операциями голова, хвост и и, то алгоритм решения этой
задачи составить невозможно.
Может быть доказано более общее утверждение.
19
Теорема. Пусть дан алгоритм, каждый, шаг
которого представляет собой приказ одного из четырех
типов:
а) к.^голова{1);
б) ft: = хвост (I);
в) k:=u(l, т, п, . . .);
г) ft: = /,
где ft — некоторое обозначение, а I, т, п, . . . — либо *
обозначения, либо конкретные слова, заключенные в
кавычки. Пусть алгоритм применен к некоторым исходным
данным. Тогда число букв в словах-результатах зависит
только от числа букв в исходных данных.
Доказательство. Проведем индукцию по
числу шагов в алгоритме. Если алгоритм содержит 0
шагов, то все верно, так как результат — это сами исходные
данные. Добавляя к алгоритму один шаг, мы вводим
новое обозначение ft. Этот последний шаг по условию
теоремы имеет тип а), б), в) или г). Поскольку слова,
обозначения которых встречаются справа от знака: =,
построены за меньшее число шагов, по предположению
индукции, число входящих в них букв зависит только от числа
букв в исходных данных. Теперь видно, что число букв
в ft тоже зависит только от числа букв в исходных
данных: во всех случаях а), б), в) и г) число букв в ft
однозначно определяется числом букв в /, т, п, . . .
Результатом построения, которое требуется
выполнить по условию задачи, должно явиться слово, число
букв которого зависит от числа различных букв в
исходном слове. Следовательно, такое построение с помощью
операций голова, хвост, w невозможно.
Сформулированную задачу можно решить, если
включить в алгоритм проверку равенств букв.
Задача 3. Пусть А={а, Ь, с}. Доказать, что, используя
только операции голова, хвост, <->, невозможно составить алгоритм
построения по данному трехбуквенному слову и в алфавите А
трехбуквенного слова v в этом же алфавите такого, что:
1° если все буквы слова и попарно различны или если они все
одинаковы, то u=v;
2° если слово и содержит ровно две одинаковые буквы, то эти
буквы дают первую и вторую буквы слова v, последняя буква слова
I/ — это третья буква слова и. .
Указание. Доказать, что если алгоритм составлен только
из приказов вида а), б), в), г) (см. теорему этого пункта), то замена
в исходных данных некоторых из букв а на букву Ъ ведет к тому,
что новые слова-результаты будут отличаться от прежних только
20
тем, что некоторые из букв а будут заменены на букву Ь. Тогда,
если в результате применения алгоритма к слову acb получается
опять слово acb, то в результате применения этого алгоритма к
слову bcb получится либо acb, либо bcb, но никак не ЪЪс.
§ 3. Запись алгоритмов, которые содержат проверки
Составляя алгоритмы, которые содержат проверки
условий, будем прибегать к условным приказам
следующего вида:
если проверяемое то что нужно сделать, иначе что нужно сде-
условие если условие вы- лзть, если уело-
полнено (приказ) вие не выполнено
(приказ)
Предписываемое таким образом действие составляет шаг
алгоритма. Иногда будут встречаться более короткие
приказы:
если проверяемое то что нужно сделать,
условие если условие
выполнено (приказ) *)
Когда условие не выполнено, такой приказ не вызывает
никаких действий (кроме, разумеется, проверки
условия).
1. Алгоритм построения кратчайшего пути.
Приступим к конструированию алгоритма построения точки С
(см. первый пример предыдущего параграфа). Условимся
о кратких обозначениях. Пусть Р, Q, R, S, Т, V —
некоторые точки. Тогда (Р, Q, R; S, T, U) означает
наличие хотя бы одной общей точки у окружностей,
заданных точками Р, Q, R и 5, Т, U. Если Q и R —
различные точки, то (Q, R; S, T, U) означает наличие общей
точки у прямой, проходящей через Q и R, и окружности,
заданной точками S, T, U. Условие наличия общих точек
у двух прямых, заданных точками Р, Q и R, S,
записывается как (Р, Q; R, S). Далее (Р; S, T, U), (P; Q, R),
(Р; Q) означают принадлежность точки окружности,
принадлежность точки прямой и совпадение двух точек.
Отношение порядка между точками Р, Q, R, которое
*) Эту и предыдущую конструкции не следует рассматривать
как фразы русского языка, так же как знак := не следует
расчленять на : и =. Выписанные конструкции — фиксируемый нами
способ обозначения условных приказов, поэтому мы вольны опустить
запятую перед то.
21
мы будем записывать в виде <Р, Q, Ry, означает, что
точки Р, Q, R попарно различны, лежат на одной
прямой и точка Q лежит между Р и R.
Будем считать, что прямая, проходящая через А, В,
и прямая L не параллельны. Позднее будет дан алгоритм,
охватывающий все случаи. Начнем с наброска алгоритма:
R: Даны точки А и В и прямая L, проходящая
через точки Р и Q. Построить точку С на прямой
L такую, что расстояние \АС\+\СВ\ —
кратчайшее;
RI: если точки А и В лежат по разные стороны от
L, то построить точку пересечения прямой L и
прямой, проходящей через А и В, обозначить эту
точку С и все закончить;
R2: построить точку D, симметричную В
относительно L;
R3: построить точку пересечения прямой L и прямой,
проходящей через А и D, обозначить эту точку С
Мы не придерживались условленных правил записи
алгоритмов. Теперь наша задача — заменить шаги
наброска последовательностью настоящих шагов. Сразу видно,
что сделать это старыми
средствами не удастся, потому что
в «шаге» R\ есть слова «и все
закончить». В этом случае мы
будем пользоваться приказом
выход. Как только дело доходит до
этого приказа, нужно
прекращать выполнение алгоритма.
Чтобы проверить условие,
лежат ли точки Л и В по
разные стороны от L, нужно
построить точку пересечения Е
прямой L с прямой,
проходящей через А и В. Если Л и Б
лежат по разные стороны от L,
то выполнено <Л, Е, By (рис. 9). RI можно заменить
тремя шагами:
Д1: Е:=П(А,В; Р, Q);
R2: если <Л, Е, By що С:=£;
R3: если <Л, Е, By то выход
Эта замена RI на три шага имеет два недостатка.
Во-первых, дважды производится проверка отношения
<Л, Е, By. (Так получается потому, что в условном
22
приказе после то располагается один приказ, а нужно
два: присваивания и выхода.) Во-вторых, вместо одного
шага наброска появилось несколько шагов. После того
как алгоритм будет составлен, первоначальный набросок
мог бы играть роль комментария к нему, и для большего
удобства хорошо бы иметь какое-то соответствие между
шагами наброска и шагами алгоритма.
Первый недостаток ликвидируется следующим
соглашением: из нескольких приказов можно сделать один,
поместив их между словами начало и конец (разделяться
приказы будут точкой с запятой). Второй —
соглашением, что обозначения шагов можно дробить. Шаг наброска
#1 может быть заменен шагами #1.1, R\.2, . . .
Рис. 10.
Первый шаг наброска заменяется («детализируется»)
так:
#1.1: £:=П(Л,В;Р, Q);
R1.2: если <Л, Е, By то начало С:=Е; выход
конец
На шаге R2 требуется построить точку D,
симметричную точке В относительно прямой L. Это можно сделать
так, как показано на рис. 10.
#2.1: F:=n.(P,P,B;Q,Q,B);
R2.2: если (В; F) то D:= П (Q, Q, В; Р, Р, В) иначе
D:=F
Шаг R2.2 нужен потому, что мы не знаем, по какую
именно сторону от прямой L расположена точка В, и в
Результате шага R2A можем получить саму точку В.
Шаг #3 запишется в виде:
ЯЗ: С:= n (A, D; P, Q)
23
Таким образом, алгоритм построения точки С
имеет вид:
R: Даны точки А, В, Р, Q. Построить точку С
на прямой, проходящей через Р и Q, такую,
что сумма расстояний \АС\+\СВ\ —
наименьшая;
RIA: E:=n(A,B;P,Q); «
#1.2: если '<Л, Е, В> то начало С:=Е; выход
конец;
Л2.1: F:= (Р, Р, В; Q, Q, В);
#2.2: если (В; F) то D: = П (Q, Q, В; Р, Р, В) иначе
D:=F;
#3: C:={A,D;P,Q)
Задача 1. Треугольник, заданный тремя своими вершинами
А, В, С, проецируется из точки О на прямую L в отрезок. Пусть
прямая задана своими точками Р и Q. Построить концы отрезка-
проекции.
2. Сравнение чисел. С помощью условных приказов
и операции отношения < легко написать алгоритмы
вычисления абсолютной величины и выбора
наибольшего из трех данных чисел.
А: Дано х. Нужно вычислить у—\х\, используя
операцию умножения и операцию отношения <;
А\: если х<.0 то #:=(—1)Xjc иначе у.—х
т: Даны х, у, z. Нужно вычислить ы=тах(д:, у, г)
с помощью операции отношения <;
ml: если х<у то v:=y иначе v:=x;
т2: если v<.z то u:=z иначе u:—v
Шаги т\ и т2 можно записать в виде одного шага:
если х<у то
если у<л то u:—z иначе и:=*у иначе
если х<л то u:=z иначе и:=х
Этот приказ соответствует «дереву возможностей»,
изображенному на рис. 11. Подобные приказы выполнять
трудно, поскольку трудно их понимать. Лучше
стараться обходиться более ясными конструкциями. Понимание
конструкции вроде рассмотренной особенно затрудняют
условные приказы, стоящие после то. Каждый такой
условный приказ имеет смысл заключать между начало
и конец. Символы начало и конец играют роль скобок
для приказов и часто облегчают понимание структуры.
Перепишем рассмотренный условный приказ, расставив
в нем символы начало и конец
24
если х<у то начало
если y<.z то и:=г иначе и:=у
конец
иначе если x<.z то и:=г иначе и:=х
Задача 2. Анализ ситуации по «дереву возможностей»
(рис. 11) в двух случаях приводит к выбору г в качестве наибольшего,
в одном случае — к выбору лив одном случае — к выбору у.
Означает ли это, что у г больше шансов оказаться равным max (х, у, г)?
Задача 3. Даны три числа х, у, г. Нужно найти
min(max(x, у), тах(*, г), тах(у, г))
с помощью операции отношения <. Написать алгоритм решения.
Как можно коротко словами охарактеризовать получаемое значение?
Ответ. Второе по величине из х, у, г.
х<у
Нет
и:=Х
3. Выбрасывание повторяющихся букв. Пусть дано
некоторое трехбуквенное слово, которое нужно
преобразовать так, чтобы из повторяющихся букв оставалась
только одна. В алгоритме будем пользоваться операцией
равенства слов. Знак этой операции, как обычно, =.
Разберем слово на буквы и сравним их. Назовем этот
алгоритм S:
S: Дано трехбуквенное слово т. Пользуясь операциями
голова, хвост, ", =, построить слово v, в
которое каждая буква из т входит ровно один раз;
х:=голова(т);
п:~ хвост (т);
у: =голова («);
г: = хвост (п);
если y—z то ы:=г иначе и:=п;
SU
S2:
S3:
S4:
S5:
25
S6: если х=у то о:=»и иначе
если x=*z то v.—и иначе и: = ^(х, и)
Слово и, которое возникает после выполнения S5
представляет собой две последние буквы исходного слова'
если эти буквы различны. Если эти буквы одинаковы, тс
слово и—это одна буква. На следующем шаге S6 к ело.
ву и прибавляется еще одна буква — первая буква слова
т, если только она не входит в уже построенное слово п.
Задача 4. Составить алгоритм выбрасывания из трехбук.
венного слова всех равных между собой букв. Таким образом:
возможно, что результатом будет пустое слово, которое мы уговори,
лись обозначать « ». Доказать, что слово, которое получается t
результате применения алгоритма, не может состоять из двух букв.
§ 4. Различные наборы операций
Об алгоритме решения задачи на построение можне
говорить только тогда, когда ясно оговорен набор one!
раций. Переход к другому набору может привести, \
частности, к тому, что задача перестанет иметь решение,
1. Построения с помощью одной линейки или одного'
циркуля. Сузим набор операций: будем считать, что
в нашем распоряжении имеется операция выделени,1;
точки пересечения двух прямых и операция выделени;
«произвольной» точки из области, границу которой об.
разуют прямые, лучи и отрезки. Помимо этого, будек
считать, что по-прежнему имеется возможность распоз|
навания равенства точек, наличия пересечения дву>
прямых и принадлежности точки прямой, а для любы>
точек Р, Q, R — истинности отношения порядке
<Р, Q, R>. Построения с таким набором естественно
называть построениями с помощью линейки. Очевидно,
что при переходе от построений с помощью циркуля i
линейки к построениям с помощью одной линейки кру:
разрешимых задач не может расшириться. Оказываете'
этот круг сужается: существуют построения с помощы
циркуля и линейки, которые невозможно осуществить i
помощью одной линейки.'
Пример. Дан отрезок с концами А я В, найти е£
середину.
Пусть существует алгоритм построения середины 1
помощью линейки. Пусть в процессе построения к
точкам А, В добавляются точки С, D, . . ., Р и точка Р-"
середина отрезка А, В.
26
Возьмем произвольную точку 5, не лежащую в
плоскости построения а, и произвольную плоскость т, не
проходящую через S и обладающую следующими
свойствами:
Г т не параллельна о;
2° ни один из отрезков SA, SB, SC, SD,
параллелен т;
3° отрезок Л б не параллелен т;
4° любая точка F из числа А, В, С,
пересечения прямой, проходящей через S и
скостью т лежат по одну сторону от S.
SP не
Р и точка
F, с пло-
Рис. 12.
Если дана конечная совокупность отрезков, то
всегда найдется плоскость, не параллельная ни одному из
этих отрезков, поэтому т со свойствами Г—4° суще-
ствует.
■muJ°4cH A' B' C' D' * ' •' Р проецируются с помощью
А>^чк"6 "3 плоскости а в плоскость т. Получаются точки
ппп * ' ' "' ^'" Всякая прямая в плоскости а,
"Роходящая через какие-нибудь две точки из числа
рассматриваемых, скажем через А и В, проецируется в
прямую, проходящую через А' и В'. Точка части плоскости а,
раница которой состоит из прямых, лучей и отрезков,
доходящих через какие-то пары точек из А, В, С,
< ■ • -, Р, проецируется в точку части плоскости т, гра-
27
ница которой является проекцией границы части
плоскости а. Равные точки и только они проецируются в равные.
Свойство принадлежности точки прямой тоже
сохраняется при проецировании. Если выполнено <Л, В, />, то
выполнено и <Л', В', /•">. Все это вытекает из 1°—4°
(рис. 12).
Из сказанного следует, что точки С", D', . . ., Р'
можно рассматривать как точки, последовательно
построенные в плоскости т из данных точек А' и В' с помощью
имеющегося алгоритма. Поэтому точка Р' должна быть
серединой отрезка А'В', но это невозможно, так как
отрезок А'В' не параллелен отрезку А В.
Задача 1. Доказать, что не существует алгоритма построения
с помощью линейки точек пересечения двух данных заведомо
пересекающихся окружностей. Окружность задается прежним способом.
Указание. Трюк с проецированием здесь не годится —
окружность не проецируется, вообще говоря, в окружность".
Воспользоваться следующим: умей мы строить точки пересечения
окружностей, мы сумели бы найти середину любого отрезка, а этого
мы не умеем.
Представляется неожиданной следующая
Теорема Мора — Маскерони *). Все, что можно
построить с помощью циркуля и линейки, может быть
построено с помощью одного циркуля.
Мы ограничимся тем, что точно выясним смысл
утверждения теоремы.
Пусть имеются два набора операций. Утверждение,
что любая задача на построение, разрешимая операциями
первого набора, разрешима и операциями второго набора,
будет доказано, если, например, для каждой операции
первого набора будет найдено выражение (в виде
алгоритма) через операции второго набора.
Построения с помощью циркуля и линейки
предполагают, кроме построений точек пересечения и касания,
еще выбор «произвольной» точки части плоскости и
проверку некоторых отношений между объектами. Необ-:
ходимо установить, какие операции, кроме построения
общих точек двух окружностей, можно выполнять в
рамках построений с помощью одного циркуля. Естественно
считать, что выбор «произвольной» точки может
осуществляться из части плоскости, граница которой состоит
*) Г. Мор — датский математик XVII века, автор книги «Дат'
ский Евклид». Л. Маскерони — итальянский математик XVIII века,
автор книги. «Геометрия циркуля».
28
и3 построенных окружностей и дуг. Проверять можно
наличие общих точек у двух окружностей,
принадлежность точки окружности и совпадение двух точек. В
качестве аналога отношения порядка между тремя точками
здесь можно взять, например, такое отношение между
двумя окружностями: «первая окружность целиком
лежит в круге, ограниченном второй окружностью»
/в рамках построений с помощью циркуля и линейки
истинность этого отношения проверяется без труда).
Полное доказательство теоремы Мора — Маскерони
можно найти в книге Аргунова и Балка «Геометрические
построения на плоскости», Учпедгиз, 1957. Авторы этой
книги рассматривают операции, которые несколько
отличаются от наших, но их доказательство нетрудно
преобразовать в нужное нам.
2. Операции над числами. Рассмотрим множество
рациональных или действительных чисел, на котором
определены операции: сложение, умножение, деление и
операция sign, заданная соотношением
(1, если л:>0,
О, если х = О,
— 1, если х < 0.
Тогда алгоритм вычисления абсолютной величины может
быть составлен так:
А': Данох, вычислить у=\х\ операциями сложения,
умножения, деления и sign;
А'\: у:=х sign*
Из четырех операций мы использовали только две.
Задача 2. Составить алгоритм вычисления тах(л;, у) с
помощью операций сложения, умножения, деления и sign.
Указание. Предварительно доказать равенство
тах(*. у) = *+У + (*-У>»'8"(*-У> ,
Задача 3. Составить алгоритм вычисления тах(*, у) с
помощью операций сложения, умножения, деления и абсолютной
величины.
Указание, max (0, х) = J '.
3. Обход досок шахматными фигурами. Известно
много задач об обходах шахматных досок различными
Фигурами. Примером может служить следующая задача:
в левом нижнем углу шахматной доски 3x4 помещена
29
ладья. Требуется обойти ладьей доску, проходя чере;
каждое поле ровно один раз. Последним ходом ладья
должна быть установлена на одно из двух полей, сосед,
них исходному.
Задачи такого рода требуют разработать маршрут
движения фигуры. Естественно считать, что объект здесь --
некоторый маршрут, т. е. упорядоченный набор ходов.
Операции — продление маршрута на один ход и, бьщ
может, некоторые проверки. Ход можно изображав
Рис. 13.
обозначением поля, на которое он приводит, а
упорядоченный набор ходов — словом специального вида. Ecu
вертикали отмечаются (в случае доски 3x4) а, Ь, с, d, г
номера горизонталей — 1, 2, 3, то маршрут — это слове
в алфавите {а, Ь, с, d, 1, 2, 3}. Например, маршрут
изображенный на рис. 13, можно представить словом аЗЬЗЬ2,
На самом деле, коль скоро в нашем распоряжении
имеются операции, позволяющие продлить маршрут на
любой ход, мы можем не интересоваться способом
изображения хода. Пусть нам даны операции над словами-
маршрутами \(М, п), 1(М, п), ->(М, я), ч-(М, п\
Каждая из этих операций продлевает слово-маршру"
М на один ход, п — это число, указывающее на сколько
полей вверх, вниз, вправо или влево передвигаете!;
ладья.
Алгоритм решения поставленной задачи можно описать
с помощью данных операций следующим образом:
30
JI: Построить I — слово-маршрут обхода доски
3x4 ладьей;
JII: Л: = « »;
Л2: В:=НЛ, 2);
ЛЗ: С:—+(В, 1); "
Л4: D:=1(C,1);
Л5: £: = —(D, 1);
Д6: F: = f(£, 1);
Л7: G:= —(F, 1);
Л8: Я:=ИО, 2);
Л9: /: =*-(Я, 2)
Задача 4. Нарисовать предложенный маршрут.
Изменение набора операций в задачах обхода
шахматных досок естественно возникает при переходе к
другой фигуре.
Рис. 14.
Прежде чем перейти к другой фигуре (коню), укажем
все доски, для которых возможен обход ладьей.
Если у доски хотя бы одна сторона четная, то обход
ЛаДьей возможен. Маршрут будет представлять собой
гРебенку, приложенную к четной стороне. На рис. 14
приведен маршрут обхода доски 8x8. Если обе стороны
31
доски нечетные, то обход невозможен. Для
доказательства перейдем от ладьи к менее подвижной фигуре, ко.
торая также передвигается по горизонталям и
вертикалям, но только на одно поле. Понятно, что если можно
обойти доску ладьей, то можно обойти ее и новой фигу,
рой: каждый длинный ход заменяется
последовательностью коротких. Пусть поля доски окрашены, как
обычно, в черные и белые цвета. Новая фигура с каждым,
20
27
46
3?
48
53
10
1
45
38
21
28
3
2
49
58
28
19
36
47
62
55
64
11
39
44
29
22
3
8
57
50
18
25
40
35
54
81
12
7
43
32
23
30
15
4
51
58
24
17
34
41
60
53
6
13
33
42
31
16
5
14
59
52
Рис. 15.
ходом меняет цвет поля. Следовательно, если существуй
ет требуемый маршрут, то черных и белых полей поров|
ну; однако это не так, если общее число полей нечетно.|
То же самое доказательство проходит для случая;
когда изучаются обходы конем: конь, как и введенная
новая условная фигура, меняет цвет поля при каждом
ходе. Поэтому, если общее число полей доски нечетно,1
то невозможно обойти ее конем, побывав на каждом поле
ровно один раз и закончив обход на поле, с которого
одним ходом можно перейти на начальное.
Обходы конем квадратных досок 6x6, 8x8, ...
возможны, но, видимо, трудно представить их
единообразно, как сделано для ладьи с помощью рис. 14. №
рис. 15 приводится обход конем доски 8x8, предложен-;
ный Л. Эйлером.
32
Существует доказательство, что доску 4x4, и вообще
\%п нельзя обойти конем, побывав на каждом поле ровно
один раз и закончив обход на поле, с которого можно
перейти на начальное одним ходом. Это доказательство
основано на раскрашивании доски в четыре цвета (см.,
ДО. Гарднер, Математические новеллы, М., 1974).
Задача 5. Разработать маршрут обхода конем доски 6x6,
расставив номера проходимых полей как это сделано на рис. 15.
* * *
Обсуждая обходы доски различными фигурами, мы
использовали то, что все маршруты, первый из которых
состоит из одного хода с начального поля, а каждый
следующий получается продолжением предыдущего на один
ход коня или условной фигуры, похожей на ладью,
обладают свойством «если обойдено нечетное число полей,
то последнее поле одного цвета с начальным, иначе —
противоположного цвета». В доказательствах
невозможности алгоритмов часто используется следующий общий
прием. Формулируется свойство Р, которым обладают
объекты — исходные данные. Показывается, что если
Si, Si, . . ., Sm— некоторые объекты, обладающие
свойством Р, и если Sm+i— объект, который может быть
построен применением одной операции к каким-то из
объектов Si, S2, . . ., Sm, то Sm+i тоже обладает
свойством Р. После этого показывается, что объект, который
нужно построить, свойством Р не обладает.
Свойства, которые сохраняются у рассматриваемых
объектов после применения к ним операций заданного
набора, называются инвариантными (неизменными)
относительно этого набора операций.
Иногда инвариантное свойство удается выразить при
помощи некоторой "функции F, определенной на
рассматриваемых объектах и принимающей значения в
некотором множестве Q. Функция F должна удовлетворять
следующему условию, если auait . . ., ап— такие
объекты, что F(a1)=F(a2)=. . .=/r(am)=co gQ, и если am+i
получается применением к некоторым из аи . . ., ат
одной из операций заданного* набора, то F(am+i)=d).
Тогда «F(a)—m— свойство объектов, инвариантное
относительно допустимых операций. В этом случае
функцию F называют инвариантом.
Рассмотрим такой пример. Дана таблица 4x4,
заполненная знаками + и — (рис.- 16).
С. А. Абрамов
33
Разрешается производить две операции над таблицей:
Г заменить в некоторой строке каждый + на — и
наоборот;
2° заменить в некотором столбце каждый 4- на — и
наоборот. Существует ли последовательность операций,
переводящая данную таблицу в таблицу, которая
изображена на рис. 17?
+
+
+
4-
.—
+
+
+
"Т
+
~Ь ; +
+
+
+
+
V
+
+
+
+
+-
+
+
+
+
+
+
+
Рис. 16. Рис. 17.
Оказывается инвариантом здесь будет произведение
всех элементов таблицы, получающейся из
рассматриваемой заменой каждого 4- на 1 и заменой каждого — на —1.
Задача 6. Доказать, что предложенная числовая функция
действительно является инвариантом относительно оговоренного
в условии набора операций. Дать ответ на поставленный вопрос
о существовании последовательности операций.
§ 5. Избыточность набора операций
1. Окружность через три точки. В § 4 показано, что
с помощью циркуля и линейки можно решать те же самые
задачи на построение, что и с помощью одного циркуля.
В этом смысле соответствующие наборы операций
эквивалентны. Но один из наборов более удобен: если
использовать и циркуль и линейку, то алгоритмы будут
получаться более короткими и понятными.
Возникает естественное желание решать задачу на
построение с помощью одного циркуля следующим
образом. Сначала составить алгоритм требуемого построения,
предполагающий применение и циркуля и линейки.
Затем составить алгоритмы, выражающие операции, кото-
34
рые используют линейку, через операции, которые
используют лишь циркуль.
Впредь мы будем часто поступать именно так!
описывать алгоритм не сразу в виде последовательности
операций данного набора, а в виде последовательности
операций, набор которых нам кажется естественным для
решения рассматриваемой задачи. Все операции из
нового набора должны быть в конечном счете выражены
через заданные операции в виде алгоритмов.
Вернемся к построениям с помощью циркуля и
линейки, и рассмотрим следующий пример. Нужно
построить центр окружности, проходящей через три
данные точки, не лежащие на одной прямой. Хорошо
известно, что для решения задачи нужно рассмотреть
треугольник с вершинами в данных точках. Искомая
точка — пересечение перпендикуляров, проходящих через
середины сторон треугольника. Алгоритм решения этой
задачи можно изобразить так:
Р: Даны три точки А, В, С, не лежащие на одной
прямой. Построить точку Т — центр
окружности, проходящей через А, В, С;
Р1: построить точки U, V перпендикуляра,
проходящего через середину отрезка с концами А, В (с
помощью алгоритма П);
Р2: построить точки R, S перпендикуляра,
проходящего через середину отрезка с концами А, С
(с помощью алгоритма П);
РЗ: T:=n(t/, V; R, S)
П: Даны две различные точки D, Е. Построить точки
X, Y, лежащие на перпендикуляре, ■ проходящем
через середину отрезка с концами D, Е\
/71: X:=n(D,D, E; E, E, D);
П2: У: = П (Е, Е, D; D, D, Е)
Если бы мы попытались детализировать шаги Р1 и
Я2, то пришлось бы дважды выписать шаги П\, П2,
меняя лишь буквенные обозначения точек.
Предложенный вариант алгоритма хорош и в другом отношении —
он отражает естественное стремление свести задачу к
более простым подзадачам.
Задача 1. Используя алгоритм С (§1), описать алгоритм
построения точки пересечения медиан треугольника с вершинами
А, В, С. Поскольку применение алгоритма С приводит к
построению одной точки (в отличие от алгоритма Л), можно при записи
требуемого алгоритма пользоваться приказами вроде Т:=С(А, В).
2*
35
2. Максимальное из трех чисел. Эта задача
разбиралась в § 3. Теперь рассмотрим возможности сведения
ее к подзадачам. Говорилось, что решение этой задачи
состоит в Нескольких нахождениях максимального из
двух чисел. Если имеется операция М (х, у),
вырабатывающая наибольшее из двух данных значений, то
описание алгоритма выбора максимального из трех можно
сделать таким:
/: Вычислить е, равное максимальному значению из
трех данных а, Ь, с;
/1: d:=M(a, b);
12: e:-M(d,c)
Если в нашем распоряжении нет операции М, то
нужно составить алгоритм Л1, который сводит выбор
наибольшего из двух чисел к последовательности
допустимых операций. Пусть среди допустимых операций есть
операция отношен и я<- Тогда алгоритм М записывается
в один шаг:
All: если х<у то г:=у иначе г:=х
Если среди допустимых операций нет операции
отношения, но есть операция sign вычисления знака, то
можно воспользоваться алгоритмом, о котором шла речь
в задаче 2, § 4.
Задача 2. Даны х, а, Ь, с, й. Составить алгоритм вычисления
у = ах3-\- Ьхг-{- сх-\- d
с использованием следующего набора операций:
1° сложение,
2° вычитание,
3° возведение в квадрат (обозначение: квадрат(()),
4° деление на два (обозначение: половина^)).
Составить вспомогательный алгоритм вычисления произведения
двух чисел.
Указание. (H-s)2=/2-f2/s+s2.
3. Переправа через реку. Двое друзей отправились на
экскурсию и каждый взял с собой сына. В пути они
должны были переправиться через реку с помощью
складной лодки, которая могла перевезти самое большее
100 кг. Каждый из друзей вместе с рюкзаком весит
100 кг, а каждый из мальчиков 50 кг. Каким образом они
переправились через реку?
В условии не сказано, сколько весит каждый отец и
каждый рюкзак. Более того, не сказано, одинаковы ли
по весу рюкзаки. Поэтому нам не остается ничего луч-
36
шего, как считать, что операция — это либо переправа
одного мальчика, либо обоих мальчиков, либо одного
из отцов вместе с его рюкзаком. Более точно, будем
считать, что нам даны операции добавления к уже
построенной последовательности переправ S новой
переправы:. О (г, S) — переправа отца с его рюкзаком (i —
это 1 или 2 в зависимости от того, первый или второй
отец переправляется); m(i, S) — переправа мальчика
(/ — по-прежнему 1 или 2); мм (S) — переправа двух
мальчиков.
Здесь имеется в виду задача построения некоторого
слова. Операция добавляет к слову несколько букв,
обозначающих переправу.
Если удастся решить подзадачу переправы одного
из отцов вместе с его рюкзаком так, чтобы мальчики
после этого оказались на исходном берегу, то мы сможем
решить и всю задачу. Пусть алгоритм решения такой
подзадачи существует. Обозначим его F. Тогда
алгоритм решения исходной задачи прост:
G: Построение последовательности переправ U двух
отцов с рюкзаками и двух сыновей в складной лодке}
G1: Л:=« »;
G2: B:*=F(l,A);
G3: G:=f (2, В);
G4: U:=mm(C)
Теперь нужно составить алгоритм F. Отец назад с
рюкзаком не поплывет, придется одному из мальчиков лодку
переправлять обратно. Для этого он должен пересечь
реку до переправы отца. Отведет лодку назад второй
мальчик.
F: Дано число i, равное 1 или 2, и последовательность
переправ W. Нужно получить последовательность
V, добавив к W переправы, необходимые для
перевозки i-го отца и возвращения мальчиков с лодкой
на исходный берег;
F\: D:=mm(W);
F2: Е:=м{\, D);
F3: /:=0(j, £);
£4: V:=m(2, I)
Задача 3. В алгоритмах С и F вместе 8 шагов. Сколько
бы получилось шагов в G, если бы мы решились на отказ от
алгоритма F и детализацию шагов G?
Задача 4. Можно ли в F2 заменить 1 на 2 и в /74—2 на 1?
Можно ли сделать только одну из этих замен?
37
* * *
Резюмируем и повторим главное из сказанного.
Заданный набор операций может быть избыточным — это
значит, что из него можно выбрать поднабор, операциями
которого решаются все задачи, которые можно решить
операциями исходного набора. Однако избыточный
набор почти всегда оказывается более удобным для
разработки алгоритмов. Поэтому мы принимаем соглашение,
по которому можно расширять имеющийся набор
операций. При таком расширении новые операции должны
быть сами представлены как алгоритмы.
Принятое соглашение позволяет более интенсивно и
просто применять составленные ранее алгоритмы.
Конструирование хорошего алгоритма — это в значительной
мере умелое сведение задачи к подзадачам. Причем,
когда мы составляем основной алгоритм, мы совершенно
не заботимся о том, как устроены вспомогательные
алгоритмы, а когда составлен вспомогательный алгоритм,
становится безразличным, как и в каких задачах он
будет использован.
Сведение исходной задачи к отдельным подзадачам и
составление алгоритмов решения отдельных подзадач,
а не всей задачи сразу имеет два преимущества:
во-первых, сохраняется ясная структура алгоритма, во-вторых,
решение основной задачи может несколько раз сводиться
к некоторой подзадаче и при детализации шагов
придется многократно почти дословно переписывать
последовательность операций.
Строго говоря, мы не всегда обращаемся со
вспомогательными алгоритмами, как с операциями. Применение
операции заданного набора приводит к построению
одного объекта, а применение вспомогательного
алгоритма может дать и несколько объектов —• например две
точки, определяющие перпендикуляр, проходящий через
середину отрезка. Если применение вспомогательного
алгоритма приводит к построению одного объекта, то
ссылку на него (будем также говорить «обращение к
нему») записывать очень удобно — вроде операции или
функции. В других случаях приходится прибегать к
менее выразительным формам записи.
Глава II. ЦИКЛ
Здесь будет рассказано о способах точного описания
таких алгоритмов, которые в разговорной речи
объясняются с помощью слов «и так далее».
§ 1. Ограниченность поля зрения
Начиная с этого момента, будем исходить из
предположения, что выполняющий алгоритмы может держать
в своем поле зрения лишь ограниченное число объектов.
Это предположение находится в соответствии с
представлением об ограниченности памяти (здесь и далее память —
это некоторое хранилище объектов, например мозг,
лист бумаги, доска, магнитофонная лента, электронное
устройство). Для нас это будет означать, что можно
пользоваться только ограниченным числом обозначений.
Точная граница этого числа нас интересовать не будет.
Мы просто будем стараться составлять алгоритмы
возможно экономнее. Сейчас будет принято соглашение,
которое позволяет забывать объекты, уже сыгравшие свою
роль и для дальнейших построений не нужные.
1. Построение отрезка в пять раз больше данного.
Эту задачу решить легко:
V: Дан отрезок с концами А, В. Нужно построить
точку С такую, что отрезок АС в пять раз
больше АВ;
VI: D:=n (В, А; В, А, В);
V2: £:=П (В, A; D, А, В);
V3: F:=n (В, А; Е, А, В);
V4: С:=Г1 (В, A; F, А, В)
На рис. 18 рядом с точками отмечены номера шагов, на
которых эти точки возникают.
39
Задача 1. Можно ли шаг V2 заменить на E: = f](A, В; D,
А, В)? Можно ли его заменить на Е: — (](В, A; D, В, Л)?
В алгоритме V точка D, построение которой
описывается шагом VI, используется только на шаге V2. После
того, как этот шаг выполнен, она становится ненужной.
Однако тот, кто будет выполнять алгоритм, обязан
следовать этому алгоритму неукоснительно. Он должен
помнить об этой точке и о ее обозначении до конца
выполнения. Для экономии памяти обозначение, ранее
закрепленное за некоторым объектом, можно закреплять
за другим объектом. При этом первый объект теряет свое
прежнее обозначение. Если он не имел других
обозначений, то он забывается (стирается из памяти).
о о -о— о ■ о о
А В Д(0 £(?,) F(3) Ф
Рис. 18.
Алгоритм V можно переделать в алгоритм V, который
предполагает исключение точек, ставших ненужными:
VI: D:=f](B, А; В, А, В);
V'2: C:={)(B,A;D,A, В);
V'3: Z3:=n (В, А; С, А, В);
Г4: С:=Л (В, A; D, А, В)
Мы пойдем еще дальше — будем употреблять приказы
вроде С:=Л (А, В; С; А, В). Понимать это нужно так,
что сначала строится новая точка Г) (А, В; С, А, В), а
затем она получает обозначение С. Та точка, которая
раньше обозначалась С, забывается. Еще раз перепишем
алгоритм:
V"U С:=П (В, А; В, А, В);
V"2: С:=П(В,А;С,А,ВУ,
V"3: С:=П(В, Л;С, Л,В);
Г'4: С:=П(В, А; С, А, В)
На рис. 19 изображены результаты выполнения шагов
алгоритма V". Получилось, что никаких дополнительных
обозначений для запоминания промежуточных точек не
нужно.
Задача 2. Переписать алгоритм еще раз так, чтобы по-
прежнему не было дополнительных обозначений и ^тобы алгоритм
состоял всего из трех шагов.
Указание. 5=2x2+1.
40
2. Вычисление значений многочленов. Если нужно
вычислить у=ах*+Ьх+с по данным а, Ь, с, х с помощью
операций умножения и сложения, то, как отмечалось,
удобно воспользоваться равенством у=х(ах+Ь)-\-с.
v"i:
о о о
А В С
у"г: „
оо о
А В С
О О 'О
А В С
0 0 В
А В С
Рис. 19.
Применяя приемы экономии обозначений, можно
прийти к такому алгоритму:
/: Даны а, Ь, с, х. С помощью операций сложения
и умножения вычислить у=ах*-\-Ьх-\-с;
t\: у:=ах;
П: у:=у+Ь;
/3: у:=ху;
/4: у:=у+с
При выполнении алгоритма буква у последовательно
обозначает ах, ax-j-b, ax2+bx, ax2-\-bx+c. Введение
промежуточных обозначений часто позволяет сокращать
количество выполняемых операций, поэтому не стоит
особенно увлекаться экономией обозначений.
Рассмотрим, например, задачу вычисления величин и=\ —
— 2х+3хг—4х3 и и=1+2ж-гЗхг+4л:3, где х — данное
число.
Величины и и v можно вычислить независимо друг от
друга. Для этого преобразуем их следующим образом:
«=1+л:(—2+х(3+х{— 4))), v=\+x(2+x(3+4x)), тогда
алгоритм решения этой задачи будет иметь вид:
41
uv: Вычислить и=\—2x-\-3x*—4л:3, а=1+2л:4-3*2+
+4л;3 по данному х с помощью операций
умножения и сложения;
uv\: и:=хх (—4);
uv2: ы:=3+ы;
uv3: и:—хи\
uv4: u:=—2+и;
uv5: и:=хи;
uv6: и: = 1+«;
uv7: y:=4x;
uv8: у:=3+у;
uv9: v:=xv;
uv\0: v:=2+v,
uvll: v:=xv\
uv\2: v: = l+v
Удобно представить и и v следующим образом:
и=(1+3х*)—(2x+4x0=(l+3x2)+(—1)^(2+4^),
v=(1+Зх2)+(2л:+4г!)=(1+Зл;2)+л: (2+4х2).
Преобразованные uwv содержат одинаковые компоненты.
Значение каждой компоненты z=l+3x2 и у=х(2+4х2)
можно вычислить один раз и запомнить для повторного
употребления.
vul: у:=хх;
vu2: #:=4г/;
шЗ: у:=2+у;
ш4: у:=ху;
vub: z:=xx\
шб: z:=3z;
vul: z: = l+z;
vu8: v:=z-\-y\
vu9: y:={—\)y\
vulO: u:—z-\-y
Сэкономлены две арифметические операции.
Задача 3. Алгоритм vu предписывает дважды вычислять
значение х2 (см. шаги vul и vub). Переписать алгоритм, сократив
его на один шаг и ликвидировав перевычисление. Дополнительные
обозначения не вводить.
Указание. Первые два шага нового алгоритма составляют
приказы г:=хх; y:=4z.
■ На примере алгоритмов uv и vu видно, что иногда
приходится выбирать между экономией памяти и эконо-
42
мией операций. В случаях, когда введение небольшого
числа дополнительных обозначений позволяет не
повторять одни и те же построения несколько раз, мы будем
предпочитать алгоритмы типа vu. В то же время мы не
будем вводить новых обозначений, когда в этом нет
необходимости.
Задача 4. Составить еще один алгоритм вычисления
значений «но. Новый алгоритм должен требовать выполнения не более 9
операций и не более одного дополнительного обозначения.
Указание. Воспользоваться решением задачи 3. Далее
исключить г из алгоритма, заменив его на и.
3. Снова обход доски ладьей. В результате
выполнения алгоритма Л (гл. I, § 4) оказываются
построенными не только требуемый маршрут /, но и еще 8 маршрутов.
Маршруты А, В, С, D, E, F, G, Н, I таковы, что первый
из них пуст, а каждый следующий получается из
предыдущего добавлением одного хода. Ясно, что после того,
как добавлен ход и построен новый маршрут, прежний
маршрут можно забыть. Перепишем алгоритм Л, экономя
обозначения:
Л: Построить I — маршрут обхода доски 3x4 ладьей,
который начинается в левом нижнем углу и
заканчивается на соседнем справа поле;
Л\:
Л2:
ЛЗ:
Л4:
Л5:
Л6:
Л7:
Л8:
Л9:
/
/
/
/
/
/
/
/
/
— « »;
= t(/, 2);
= -*(/, 1)
= ИЛ П;
= -(/, 1)
= t(/, 1);
=—(/. 1)
= ИЛ 2);
= —(/, 2)
•Выписывать многократно приказы присваивания
одной и той же структуры — занятие утомительное.
Хотелось бы составлять подобные алгоритмы из шагов вроде
Л2: вверх (2),
чтобы при выполнении такого шага к набору уже
сделанных ходов / (который явно не упоминается)
добавлялся ход на два поля вверх.
Такую возможность мы получим, составив
вспомогательные алгоритмы вверх, вниз, вправо, влево. Эти алго-
43
ритмы предназначены для выполнения действий над
объектом (маршрутом /), который не входит в число
аргументов. Эти алгоритмы сами заботятся о сохранении
результата — ему дается обозначение /. Поэтому
обращения к таким алгоритмам устраиваются в виде
приказов, а не в виде операций.
вверх: Дано число п. К маршруту I добавить ход на
п полей вверх. Результат должен получить
обозначение I;
вверх 1: /: = f (/, п)
К алгоритму вверх можно обратиться из любого
алгоритма, в котором рассматривается маршрут /.
Точно так же могут быть составлены алгоритмы вниз,
вправо, влево.
Алгоритм обхода доски 3x4 ладьей теперь можно
представить в более естественном виде:
Л'1: /:=« »;
Л'2: вверх (2);
Л'З: вправо (1);
Л'А: вниз (1);
Л'Ъ: вправо (1);
Л'6: вверх (1);
Л'1: вправо (1);
Л'Ъ: вниз (2);
Л'9: влево (2)
Задача 5. Некто стоит у реки с чайником емкостью 3 л и с
кувшином — 5 л. Каким образом он может отмерить 4 л? Каков
алгоритм построения последовательности действий? Считать, что
имеются следующие операции добавления действия к имеющейся
последовательности действий S: 4K(S), K4(S), 4P(S), P4(S), KP(S),
PK(S). Эти операции добавляют соответственно действия
переливания из чайника в кувшин, из кувшина в чайник, из чайника в
реку, из реки в чайник, из кувшина в реку, из реки в кувшин.
Дополнительно составить алгоритм, использующий 6 вспомогательных
алгоритмов чк, кч, чр, рч, кр, рк, которые вообще не имеют явных
аргументов и каждый из которых добавляет к последовательности
действий / еще одно действие с, помощью одной из операций У/С,
КЧ и т. д.
* * #
- Рассматриваемые алгоритмы становятся все более
длинными. Для сокращения записи мы будем применять
конструкции вроде
С:= П (В, А; П (В, А; В, А, В), А, В),
у: = 1+3хх,
/:=->(!(/, 2), 1).
44
В результате выполнения первого приказа получится
точка С такая, что отрезок АС втрое больше отрезка АВ.
Второй приказ приводит к вычислению величины 1+Зл:г,
которая обозначается у. Наконец, третий приказ
добавляет к / два хода ладьи: на два поля вверх и на одно
вправо.
Между первой и третьей конструкцией есть сходство:
операции записываются в виде функций.
Арифметические операции традиционно записываются иначе: знак
операции ставится между (а не перед) двумя оперантами.
В первом и третьем случаях порядок выполнения
операций абсолютно ясен, во втором случае нужно знать
порядок старшинства операций. Можно было бы условиться
и арифметические операции записывать в
функциональном виде:
у: =+(1,Х(3,Х(х,х))),
но мы не будем отступать от традиции. Считаем, что
выполняющий алгоритмы знает порядок старшинства
операций.
Задача 6. Переписать алгоритм построения отрезка в пять
раз большего данного, составив алгоритм из одного шага.
Задача 7. Заменить шаги алгоритма Л одним шагом.
Задача 8. Пользуясь длинными выражениями, переписать
алгоритм vu (п. 2). Как и прежде, вычислить общие компоненты
для и и и один раз (применить дополнительное обозначение).
Обозначение, которое привлекается для описания
алгоритма, по ходу выполнения алгоритма может
обозначать разные объекты. Впредь обозначение будет
называться переменной, а обозначаемый объект — значением
переменной. Таким образом, при выполнении алгоритма
переменная может получать и менять значения.
Рассмотрим один важный пример. Пусть переменные
о и b имеют какие-то значения. Требуется описать
приказы обмена значениями между переменными а и Ь.
Два шага
Шаг i: a:=6;
Шаг i+\: b:^a
задачи не решают: обе переменные будут иметь значение,
которое раньше имела переменная Ь. Здесь нужна третья,
вспомогательная переменная:
45
Шаг i: c:=a;
Шаг t+1: a:=b;
Шаг i+2: b:=c
Задача 9. Организовать обмен значениями между
переменными а, Ь, с, d, е в соответствии с таблицей (^иаЬс) — новое
значение а должно стать равным старому значению е и т. д.
Сколько дополнительных переменных потребуется?
Если один алгоритм (основной) содержит обращение к
другому (вспомогательному), то может оказаться, что в
этих двух алгоритмах встречаются одинаковые
переменные. Будем, как правило, считать, что эти переменные
друг к другу не имеют отношения, и совпадение возникло
случайно. От этого предположения будем отказываться
только в случае, когда во вспомогательном алгоритме
специально употреблены переменные из основного
алгоритма, как в алгоритме-вверх переменная /. из
алгоритма </7». Такие переменные будем называть глобальными
по отношению к вспомогательному алгоритму.
Иногда мы будем указывать глобальные переменные в
постановке задачи. Например, алгоритм вверх
опишем так:
вверх: Дано число п. К маршруту I добавить ход на
п полей вверх. Результат. должен получить
обозначение I. Переменная I — глобальная?
вверхХ: /:=t(/, n)
С целью экономии памяти будем иногда использовать
переменные, обозначающие данные величины, для
обозначения промежуточных вычислений и даже для
обозначения результата. Например, рассмотрим алгоритм:
К'- Дано число п. Вычислить п2 с помощью операции
умножения. Результат обозначается п;
/С1: п:—пхп
§ 2. Логические выражения
1. Операции над высказываниями. В алгоритмах
мы употребляли конструкции
если . . . то . . . иначе ... (1)
если . . . то . . . (2)
Вместо первого многоточия помещались некоторые
отношения между объектами: отношение принадлежности
точки окружности, отношение равенства и неравенства
46
между числами, отношение равенства двух слов в
некотором алфавите и т. д. Отношение — это простейшая
форма логического выражения. Логическое выражение
представляет собой высказывание определенного вида.
Если переменные р, q, r имеют значения среди точек
•плоскости, то <р, q, r> — это высказывание
относительно этих значений, которое утверждает, что точки
р, q, r различны, лежат на одной прямой и точка q
лежит между точками риг. Отношение 3>1 — это
высказывание, утверждающее, что 3 больше 1, отношение
5=1 — это высказывание, утверждающее, что 5 равно 1.
Если и обозначает непустое слово в алфавите {а, Ь}, то
отношение голова (ы)=«а» — это высказывание, которое
утверждает, что первая буква слова, обозначенного и,
есть буква а.
Все высказывания можно поделить на истинные
и ложные. Высказывание 3>1 истинное, 5=1 —ложное.
Высказывания <р, q, r>, x <у-\-3, голова (ы)=«а»
могут быть иногда истинными, а иногда ложными в
зависимости от значений переменных.
Высказываниям будем приписывать значения.
Значением истинного высказывания будем считать символ И
(истина), значением ложного высказывания — символ Л
(ложь). Высказывание <р, q, О будем иметь значение И,
если, например, р и г.— различные точки плоскости и
q — середина отрезка рг. Это же высказывание будет
иметь значение Л, если р, q, r — вершины некоторого
треугольника. Значением высказывания 3>1 является
И. Значением высказывания лг<С#+3 будет Л, если,
например, х=100, г/=0. Если же х=у=\, то значение —
И. Значение высказывания голова (и)=«а» равно И, если,
например, и обозначает однобуквенное слово а. Значение
этого же высказывания равно Л, например, в случае,
когда и обозначает слово ЪЬа.
Из простых высказываний можно образовывать более
сложные следующим образом: если Р и Q — некоторые
высказывания, то Pf\Q (читается «Р и Q») — это новое
высказывание, утверждающее истинность обоих
высказываний Р и Q; PVQ (читается: «Р или Q») — это новое
высказывание, утверждающее истинность по крайней
мере одного из высказываний Р и Q; если R —
высказывание, то "| R (читается: «не R» или «неверно, что
R») — новое высказывание, утверждающее, что R —
ложное высказывание.
47
Следующие таблицы уточняют словесные объяснения:
Значение Р
И
И
л
л
Значение Q
И
л
и
л
Значение R
И
л
Значение Р Л Q
И
л
Л
Л
Значение ~~\ R
Л
И
Значение PVQ
И
и
и
л
Операции над высказываниями (логические операции)
Д| V, ~| называются соответственно конъюнкцией,
дизъюнкцией и отрицанием.
Рассмотрим примеры.
Если х и у имеют
какие-то числовые значения,
то отношения x24-«/2<U и
дс<0 являются
высказываниями относительно этих
значений. Можно
построить высказывания х2-\-уг^.
<1Л*<0 и ~]х<0. Из
этих двух высказываний
можно построить
высказывание (x2+y2^Ll/\х<
<0)V ~|л;<0. Это
высказывание истинно, если, напри-
• мер, х==у=0. Если х=—2,
у=1, то построенное высказывание ложно. На рис. 20
в заштрихованную часть плоскости (включая границу)
попали те и только те точки, значения координат х, у
которых таковы, что высказывание (х2+у^1 /\х<.0)\/
V "1 х<.0 истинно, т. е. имеет значение И.
Если р, q, r — такие точки плоскости, что выполнено
<Р> Я, О, то высказывание <р, q, х>/\~](х; г) истин-
48
но для точек той части прямой, проходящей через р, q, r
которая выделена на рис. 21.
Высказывание хвост (ы)=уЛ "1 голова (и)=«а»
истинно, т. е. имеет значение И, для таких и только таких слов
и, v, что слово и получается из слова v приписыванием
впереди одной буквы, которая не есть буква а.
В дальнейшем мы в конструкциях (1), (2) будем
применять не только отношения, но и более сложные
высказывания, подобные рассмотренным выше. Они-то
и называются логическими выражениями. Таким
образом, логическое выражение может быть построено из
отношений с помощью скобок и знаков логических
операций. Если скобки не расставлены (или расставлены, но
их расстановка не проясняет до конца структуру
логического выражения), то при вычислении значения этого
■' о о < > о <
Р 9 р
Рис. 21.
логического выражения вначале вычисляют значения
отношений, а затем выполняют логические операции в
следующем порядке: сначала ~|, потом Д. потом V-
Исходя из этого для логического выражения
<р, Я, х> Л 1 {х; г)
устанавливается следующий порядок операций:
2 1
<Р, д, х>Л~\ (х; г).
Если точки р, q, r, x суть вершины квадрата, то процесс
вычисления логического выражения можно изобразить
так:
• <Р, Я, х> Л 1 (х; г) •
'. Л Л '.
Л
49
Рассмотрим логическое выражение:
х2 + </2<1 Лх<0\/ "1 х<0.
Установим порядок выполнения логических операций:
х2 + г/2<1 /\x<0V\jc<0.
Найдем значение для х — у=\/2:
х2 + у*<;1 Ax<0V~\x<0
~И Л ' ' Л '
Л И
И
Наконец, для логического выражения хвост(и) =
= v Л "1 голова(и) = «а» имеем следующий порядок
выполнения операций:
2 1
хвост (и) = v Л ~| голова (и) = «а»,
и если u—«baab», v=«aab», то значение логического
выражения вычисляется в такой последовательности:
хеост (и) = v Л ~] голова (и) = «а»
я
2. Логические выражения в условных приказах. Пусть
точки р, <7, г таковы, что выполнено отношение <р, q, r>.
Условный приказ
еслы <р, </, х>Л ~1 (л:; г) то начало v:—x\ выход конец
вызовет присваивание v:=x и окончание построений в
том и только в том случае, если х принадлежит части
прямой, которая выделена на рис. 21.
Пусть х и у — некоторые числа. Условный приказ:
если х2+у2^\/\х<.0\/х^О то х:=х-\-\ иначе х:-~^0
вызовет увеличение х на 1, если точка с координатами
х, у попадает в часть плоскости, которая на рис. 20
заштрихована. В противном случае будет выполнено
х:=0.
60
3 а дача 1. Доказать, что логическое выражение х2-\-уг<с\/\х<
<0v*>0 принимает значение И тогда и только тогда, когда
логическое выражение х2+у*<1лх<0\/ 1#<0 принимает значение И,
Пусть и п v — некоторые слова в алфавите {а, Ъ)
ни — не пусто. Тогда условный приказ
если xeocm{u)=vЛ ~] голова(и)=«а» то «:=и
иначе v: = u
вызовет присваивание u:—v в случае, если и получается
из v приписыванием спереди буквы, отличной от буквы а.
В противном случае будет выполнено v:=u.
Задача 2. Пусть Р и Q — некоторые высказывания.
Построить высказывание, утверждающее, что «Р или Q, но не оба»,
применяя к Р и Q операции v, Л, "]•
Задача 3. Пусть R и 5 — высказывания, соответственно
• утверждающие, что Р принадлежит множеству М и что Р
принадлежит множеству N. Применяя к R и S операции V, Л* ~],
построить высказывания, утверждающие, что
а) Р принадлежит объединению М к N;
б) Р принадлежит пересечению М и N;
в) Р не принадлежит М;
г) Р не принадлежит М, но принадлежит N;
д) Р не принадлежит ни М, ни N;
е) Р принадлежит объединению М и N, но не принадлежит их
пересечению.
3. Логические переменные и функции. После
вычисления значения некоторого логического выражения мы
будем иногда присваивать это значение некоторой
переменной приказом присваивания. Пример такого приказа
/: = </?, q, х> А 1 (х) г).
Будут составляться алгоритмы, предназначенные для
вычисления логического значения. Если р —
переменная, имеющая логическое значение и В — алгоритм,
который по двум объектам позволяет вычислить
логическое значение, то мы можем рассматривать, например,
такие логические выражения:
р, В(х, у), ~\р/\В{х, у), рУ~[В{х, у) и т. д.
Таким образом, допускается, что в логическое
выражение могут входить не только отношения, но и
переменные с логическими значениями и обращения к
логическим функциям. Под логической функцией понимается
функция (алгоритм), область допустимых значений
которой не выходит за рамки двух элементов: И, Л.
'' 61
Задача 4. Проверка истинности отношения (Р, Q, R) хотя
и удобна в описаниях алгоритмов построений с помощью циркуля
и линейки, на самом деле может быть заменена другими проверками
из числа разрешенных. Для точек Р, Q, R выполнено (Р, Q, R)
тогда и только тогда, когда точки Р, Q и R различны и отрезок PR
есть сумма отрезков PQ и QR (см. задачу 2 гл. I, § 1). Написать
логическое -выражение, определяющее значение (Р, Q, R) через
значения отношений наличия общей точки у прямой и окружности;
двух окружностей и совпадения точек.
Задача 5. Пусть среди всех операций отношения между
числами допустима только <. Написать логические выражения,
принимающее значение И для тех значений переменных а и Ь, для
которых истинны отношения а—Ь, афЬ, a<b, a>b, а^Ь.
* * *
Вернемся к задаче нахождения на данной прямой L
такой точки С, что сумма расстояний |ЛС|+|£С| —
наименьшая из возможных. В гл. I, § 3 рассматривался
алгоритм, который предполагал непараллельность
прямой L и прямой, определяемой точками Л и В. Если
эти прямые параллельны, то, значит, точки Л и В лежат
по одну сторону от L. Поэтому для снятия ограничения
нужно шаги прежнего алгоритма предварить шагом,
содержащим условный приказ:
если 1 (Л, В; Р, Q) то начало . . .; выход конец
где Р, Q — точки, определяющие L, а многоточие —
это последовательность приказов, которую необходимо,
выполнить в случае, когда Л и В расположены по одну
сторону от L (шаги R2.\, R2.2, R3 алгоритма R, гл. I,
§ 3). Последовательность приказов, замененная
многоточием, в алгоритме уже присутствует и ее удобно
выделить в отдельный вспомогательный алгоритм:
W: Даны точки А и В и прямая L, заданная точками
Р и Q. Про точки А и В известно, что либо они
лежат по одну сторону от L, либо ровно одна
из них принадлежит L. Построить точку. X
прямой L такфо, что \АХ\+\ВХ\ —
наименьшее из возможных;
WX: Х:=П(Р, Р, В; Q, Q, В);
W2: если (В; X) то Х:= Г) (Q, Q, В; Р, Р, В);
W3: Х:=П(Л, X; Р, Q)
Теперь выпишем шаги алгоритма R', дающего полное
решение задачи:
R'l: если ~| (Л, В; Р, Q) то
начало C: = W(A, В; Р, Q); выход конец;
R'2: С:=Л(Л, В; Р, Q);
Я'З; если "1 (А, С, В) то C:*=W(A, В; Р, Q)
52
§ 3. Повторение действий
Из практики решения задач на построение известны
примеры, когда в описании алгоритма встречаются слова
«и так далее», «и так далее, пока» или нечто подобное,
например многоточие. Для описания такого алгоритма
недостаточно тех средств, которые применялись до сих
пор.
1. Аксиома непрерывности. В одной из аксиом
евклидовой геометрии, так называемой аксиоме
непрерывности *), утверждается следующее. Пусть А, В, С — три
различные точки, лежащие на одной прямой, такие,
—О О О О I О 0-0 0 '
A3 С
Рис. 22.
что В лежит между Л и С. Определим
последовательность точек на этой прямой так, что первая точка —
это точка В, а каждая следующая такова, что
предыдущая лежит между ней и точкой А. Расстояние между
соседними точками равно отрезку А В. Тогда в этой
последовательности найдется точка, лежащая вне
отрезка АС (рис. 22). Чтобы найти эту точку, можно
строить точки последовательности одну за другой,
откладывая отрезок А В на прямой в нужную сторону и
проверять, находится ли точка внутри отрезка АС.
Число точек, которое придется построить, определяется
как наименьшее целое п такое, что {п-\-\)\АВ\>\АС\.
Число п существенно зависит от величин \АВ\, \АС\
и может быть сколь угодно большим. Следовательно,
для описания алгоритма «строить новые точки
последовательности до тех пор, пока очередная точка
не окажется вне отрезка АС» недостаточно старых
средств.
Многократное выполнение действий предписывается
приказом повторять Р пока не В. Здесь Р —
некоторый приказ (может быть составной, т. е. вида начало
. . . конец), а В — условие (логическое выражение).
*) Иначе называемой аксиомой Архимеда.
63
Выполняется Р, затем проверяется В. Если В
удовлетворено, то выполнение приказа повторять Р пока не В
заканчивается. Иначе следующий этап: вновь
выполняется Р и проверяется В и т. д. Нам нет нужды при
решении геометрической задачи о точках А, В и С копить
все точки последовательности: ответ будет составлять
одна из этих точек, для построения каждой следующей
точки нужна только предыдущая. Это позволяет
обойтись одной дополнительной переменной.
А\ Даны три точки А, В, С. Построить точку D,
существование которой гарантируется аксиомой
непрерывности;
Ah D:=B;
А2: повторять D:= Л (В, A; D, А, В) пока не {А, С,
D)
Шаг А\ обязателен: не будь его, первая же попытка
выполнить приказ £>:=П (В, A; D, А, В) привела бы
к неприятностям, так как для построения П (В, A; D,
А, В) переменная D должна иметь значение"— точку.
Если требуется построить первую точку, лежащую
вне отрезка АС, и допускается возможность, что точка
С лежит между Л и Б, то алгоритм А становится
непригодным. В случае (Л, С, В) не нужно производить ни
одного построения новых точек, точка В — искомая.
Подправляем алгоритм А:
А'\: D:^B;
А'2: если (А, С, D) то выход;
А'З: повторять D:~ [} (В, A; D, А, В) пока не
(А, С, D)
Этот алгоритм дважды предписывает проверку
условия (Л, С, D). Для сокращения числа шагов
алгоритма в подобных случаях будем пользоваться приказом
пока В выполнять Р
Здесь сначала проверяется условие В, и если оно
удовлетворено, то выполняется приказ Р, вновь проверяется
условие Л и т. д. до того момента, когда окажется, что
условие В не удовлетворено. Алгоритм А' можно
преобразовать в алгоритм а:
ah D:=B;
а2\ пока ~](А, С, D) выполнять D:=n(5, Л;
D, Л, В);
Видим, что приказ
повторять Р пока не В
54
удобно применять в тех случаях, когда Р наверняка
должен быть выполнен хотя бы один раз. Приказ
пока В выполнять Р
хорош тогда, когда заранее неизвестно, должен ли
приказ Р выполниться хотя бы однажды.
Выписанные два приказа называются приказами
цикла или просто циклами.
Задача 1. Составить алгоритм построения последней
принадлежащей отрезку АС точки. Считать, что исходные точки А, В, С
удовлетворяют условию {А, В, С).
2. Суммы и произведения. Пусть в нашем
распоряжении имеются арифметические операции, среди
которых есть операции сложения, деления и операция
отношения = . Нужно составить алгоритм вычисления
величины. 1 + 1/2+1/3+. • .+!/«■ по данному
натуральному п. Для нахождения суммы достаточно вычислить
последовательно значения 1, 1 + 1/2, 1 + 1/2+1/3,. . . ,
1 + 1/2+1/3+. . .vf-1/n, получая каждое следующее
значение прибавлением очередного слагаемого к
предыдущему значению.
Н: Дано п. Вычислить s=l+-j+. • «Ч—'■>
HI: s:=0;
Ш: t':=0;
#3: повторять начало i:—i+l; s:=s+-r- конец
пока не i—n
Мы договорились, что алгоритм может содержать
обращения к другим алгоритмам. Это даеэе возможность
составить алгоритм S вычисления /(1)+/(2)+. . .+/(«),
считая, что / — это алгоритм, позволяющий вычислить
по любому натуральному i некоторое число.
Зада ч а ' 2. Составить алгоритм S.
Решим аналогичную задачу для произведения, а
именно, составим алгоритм вычисления /(1) ... f(n):
Р: Дано п. Вычислить p==f(l) f (2) . . . f(n), считая,
что f — некоторый алгоритм;
Р\: р: = 1;
Р2: t:=0;
РЗ: повторять начало i: — i+l\ p;=pf(i) конец
пока не i=n ■
S5
Задача 3. Почему в алгоритме Н переменная s
первоначально получада значение 0, а в алгоритме Р переменная р —
значение 1?
Алгоритм Р можно переписать, заменив последний
шаг на
РЗ: пока i<ji выполнять
начало k*=i-}-l\ p:=/)f(i) конец
Однако выполнение такого приказа включает в себя
проверку «верно ли, что 0<«», а эта проверка
лишняя, так как по условию п — натуральное число.
Задача 4. Описать алгоритм вычисления остатка от деления
неотрицательного целого а на положительное целое Ь. (Для полу-
чения результата среди чисел а, а — Ь, а — 2Ь, ... выбирается
последнее неотрицательное.) Описать логическую функцию делится
(а, Ь), принимающую значение И тогда и только тогда, когда а
делится на Ь.
3. Обход ладьей квадратной доски с четной стороной.
Рис. 14 демонстрирует обход для доски 8x8. Из рисунка
понятно, как обходить четную
квадратную доску в общем случае. Маршрут
имеет форму гребенки. Гребенка состоит
из соединенных зубьев. Зуб — это часть
маршрута, изображенная на рис. 23.
Чтобы вовремя сделать на доске поворот,
надо заметить край. У нас будет
возможность проверить четыре условия:
ладья находится на левом краю доски, на
правом краю доски, на нижнем краю
доски и на верхнем краю доски. Обозначим
их лк(С), пк(С), нк{С), вк(С)
соответственно, где С — слово, изображающее
упорядоченный набор ходов.
Будем пока считать, что в нашем
распоряжении имеется операция зуб{С),
применимая к любому маршруту, который
приводит на поле, расположенное на второй
горизонтали и на любой вертикали, кроме
самой правой. Эта операция продлевает
маршрут С, добавляя к нему зуб. Нужно
подняться на одно поле вверх, а затем пройти
несколько соединенных зубьев до правого
края доски. После этого останется пройти нижнюю
горизонталь, которую можно было бы пройти одним ходом
(приказ С: = -<-(С, п—1)), если бы мы знали значение
• • •
)
\
Рис. 23.
66
п — сторону доски и если бы у нас была операция
вычитания. Но значение п мы не знаем и арифметических
операций у нас нет. Придется двигаться ощупью: идти
влево передвижениями на одно поле до тех пор, пока
не окажемся на таком поле, следующее за которым
расположено на левом краю доски:
В\: С:=« »;
В2: C:=t(C, 1);
ВЗ: повторять начало С:~зуб{С); С:=-»-(С, 1)
конец
пока не пк(С);
В4: С:-ИС, 1);
В5: пока ~| лк (-«-(С, 1)) выполнять С:=-*- (С, 1)
Шаг ВЬ описывает проход нижней горизонтали.
Приказ повторять С: = -«-(С, 1) пока не лк(-*~(С, 1))
здесь поместить нельзя — в случае доски 2x2 шаг £5
не должен вызывать добавление каких-либо ходов к
маршруту.
Задача 5. Найти ошибку в построенном алгоритме.
Займемся алгоритмом зуб:
зуб: К данному набору ходов С приписываются
ходы обхода зуба (рис. 23);
зуб 1: пока ~\вк(С) выполнять С: = |(С, 1);
зуб 2: С:=-+(С, 1);
зуб 3: пока ~\нк({(С, 1)) выполнять С: — ЦС, 1)
Вернемся к алгоритму В. Ошибка в том, что вслед
за последним зубом не нужно делать ход вправо. Если
ВЗ заменить на
S3: пока ~]«/с(->(С, 1)) выполнять
начало С:=зуб(С); С:=->(С, 1) конец
то часть маршрута, являющаяся последним (самым
правым) зубом, не будет приписана к С. Нужно добавить
еще приказ С:—зуб {С).
Таким образом, шаг ВЗ следует заменить на
В3.1: пока ~\пк(^-(С, I)) выполнять
начало С:=зуб(С); С:=->-(С, 1) конец;
В3.2: С:=зуб(С)
Задача 6. Показать, что неправильный шаг S3 можно
заменить на
В3.1: С:=зуб (С);
В3.2: пока ~\пк (С) выполнять
начало С:=-*(С, 1); С~зуб(С) конец
Это дает определенную выгоду — не нужно специально вычислять
-»(С, 1) для применения операции пк.
67
Задача Т. Переписать алгоритм В. Считать, что дано четное
исло /г, допустимы арифметические операции +» —, < и операций
, I, «-. ->•
Задача 8. Составить алгоритм решения следующей задачи,
ользуясь операциями голова, хвост, ^, =, построить слово, полу-
шющееся из х изменением порядка букв на обратный.
Указание. Сначала значение у равно пустому слову.
Далее операцией голова от х отщепляется буква за буквой. Эти буквы
присоединяются в начало у операцией ^, при этом слово х
укорачивается^ операцией хвост. Так до тех пор, пока х не станет пустым i
словом.
* * *
Действие приказов цикла принципиально опирается '
на возможность использования одного обозначения для
ряда разных значений. Таким образом, приказы
присваивания вроде
D:=n (В, A; D, А, В), i:=i+\, C:=+-(C, 1)
удобны не только для экономии памяти.
§4. Массивы
До сих пор мы не рассматривали задачи, условия
которых содержат фразы «на плоскости дано п точек»,
или «иайти п чисел» и т. д. Во всех задачах было дано
определенное, явно указанное число точек, нужно было
найти явно указанное количество чисел и т. д. Теперь
мы займемся наборами объектов, или, как говорят,
массивами. Если рассматривается массив a*, a2, ...
..., ап, то в алгоритме можно использовать а с любым
индексом, например t, k—s+1, 1, 2+/, лишь бы
значение индекса давало целое число, лежащее в границах
от 1 до п. Эта конструкция называется переменной с
индексом.
В тех задачах, где даны массивы или требуется их
построить, как правило, разрешены некоторые
арифметические операции, так как значение индекса — число.
Мы в дальнейшем без специальных оговорок считаем
допустимыми операции сложения, вычитания,
умножения и операции отношения < и =.
1. Является ли данный многоугольник вписанным?
Пусть n-угольник задан своими последовательными
вершинами pi, рг, ..., рп. Чтобы ответить на вопрос,
является ли этот многоугольник вписанным, надо через
три какие-либо заведомо не лежащие на одной прямой
58
вершины многоугольника (например, через pi, р2, рЛ
провести окружность и последовательно проверить,
лежат ли все остальные вершины на этой окружности.
Если обнаружится, что pt (4s^i<n) не лежит на
проведенной окружности, то вершины pi+u p; + 2, • • •, рп
можно не рассматривать — и без этого ясно, что
многоугольник не является вписанным.
/; Дан многоугольник с вершинами pi, р2, ..., рп.
Определить, является ли он вписанным. Если да,
то а получает значение И, иначе — Л;
II: Vi и у2—две точки перпендикуляра через
середину отрезка ргрг (строятся с помощью
алгоритма Л (§ 3));
72: Ui и и 2 — две точки перпендикуляра через
середину отрезка р2рз {строятся с помощью
алгоритма П (§ 3));
/3: и: = П («1, «2; Vi, v2);
' 14: а:=И;
/5: /:=3;
/6: пока a/\i<.n выполнять
начало i:—i+l; a:=(pu и, и, pi) конец
Использован приказ цикла пока ... выполнять ...,
а не повторять ... пока не ..., потому, что для п—Ъ
ничего в цикле делать не нужно.
Задача 1. Можно ли без ущерба для дела в условии (/?,-; и,
и, рх) (шаг /6) /?] заменить на р2? На ps, pt, р,-_2?
Задача 2. Можно ли шаг /6 заменить на
/6: пока 1<и выполнять
начало
если ~] (р; и, и, pi) то
начало а:=Л; выход конец;
/:=ч+1
конец
Задача 3. Составить алгоритм построения правильного 12-
угольника, вписанного в окружность с центром в точке а,
проходящую через точку Ь, Вершины должны образовать массив vx, v2, . . .
. t ., а12. Должно выполняться Vy=b.
2. Построение простых множителей. Пусть дано
натуральное п. Требуется построить массив pi, р2, ...
•. .,Ph всех простых делителей числа п. Простой делитель
нужно учитывать столько раз, какова степень его
вхождения в п. Иными словами, простой делитель s должен'
встретиться в массиве а раз, где а таково, что п делится
на sa и не делится на sa+1. Можно перебрать все
простые числа из промежутка от 2 до и и для каждого из
59
них выяснить, делит ли оно п. Схема алгоритма
изображается так:
Р\: i: = l;
Р2: повторять начало
если npocmoe(i) то заполнить часть
массива;
конец
пока не i~>n
•Потребуется описать алгоритм (логическую функцию)
простоев). Пусть уже заполнена часть массива ръ ...
..., рт, и пусть выполнено npocmoe(i). Тогда нужно
проверять, делится ли п на £, £2, t3, ... и пока делится,
присваивать pm+1:=t; pm+2:=i; pm+s: = i; ... . После
этого т должно получить новое значение.
Внимательное рассмотрение задачи показывает, что
гораздо выгоднее из чисел 2, 3, ..., п выбирать делители
п и лишь для них проверять простое^). Проверка,
делится ли п на i (см. алгоритм делится в задаче 4 гл. II,
§ 3), много проще проверки, является ли число простым.
Получаем новую схему:
Р'\: £: = 2;
Р'2: повторять
начало
если делится(п, i) то
если простое^) то заполнить часть
массива;
i = i + l
конец
пока не i > п
На самом деле, проверка, является ли первое
делящее п число простым, не нужна: если бы это число
было составным, то оно делилось бы на какое-нибудь
из чисел 2, 3, ..., i—1, но тогда бы и п делилось на это
число, что противоречит способу построения i. Значит,
и вторая схема алгоритма не свободна от недостатков:
видимо, можно существенно сократить количество
дорогостоящих проверок чисел на простоту. Итак, первый
выбранный из чисел 2, 3, ..., п делитель i числа п будет
простым. Занося этот делитель в массив а раз (п делится
на ia и не делится на t'a_1) и поделив п на ia, мы
получаем новое число, набор простых делителей которого
совпадает с набором всех отличных от i простых
делителей числа п. Ясно, что новое число не делится на 2,
60
3 i и, следовательно, его наименьший отличный
от 1 делитель (который будет простым) можно
подбирать, начиная с i+l. При продолжении этого процесса
в некий момент обнаруживаем, что полученное в
результате деления на степень простого делителя число равно 1.
Это будет означать, что все простые делители уже
найдены.
Можно составить алгоритм, выполняя который
вообще не придется производить явных проверок чисел на
простоту.
Р: Дано натуральное п. Построить массив plt
р2, ..., pk простых делителей п;
PV. i: = 2;
/>2: т:=0;
РЗ: выполнять начало k:= частное (п, i);
если kxi = n то
начало
n: = k; /л: =m + l; pm: — i
конец
иначе i: = {+1
конец
пока не i >< п
Задача 3. Составить такой алгоритм построения массива
простых делителей натурального п, при выполнении которого
каждый делитель включается в массив 1 раз.
Задача 4. Составить алгоритм нахождения наименьшего
элемента данного массива alt а2, . . ., а„.
Указание. Значение наименьшего элемента и
определяется за п этапов: после выполнения i'-го этапа значение
переменной и равно значению наименьшего элемента среди аг, а2 а,-.
Первый этап состоит в присваивании и:=а1. Каждый следующий этап
выполняется с учетом значения, выработанного на предыдущем
этапе.
Задача 5. Составить алгоритм проверки, является ли
данный массив av аг,^ . ., ап упорядоченным по неубыванию: fli<a2<
<. . .<ап.
Указание. Применить прием, который применен в первом
(геометрическом) примере этого параграфа: если обнаружится, что
a,->fl/+i> то элементы а,-+2. о,-+3, . . ., ап не рассматриваются.
Задача 6. Даны два натуральных числа pug, p<Lq.
Построить массив цифр clf с2 с„ и числа п, т такие, что cv . . ., ст
— цифры непериодической части, а ст + 1, с,л + 2, . . •, сп — цифры
периодической части десятичной дроби, равной plq,
3. Множество, массив, слово. Понятия множества
(конечного) и массива не тождественны. Во-первых,
множество не содержит повторяющихся элементов, а
массив может их содержать (более того, может быть
61
так, что все элементы массива равны между собой).
Во-вторых, элементы множества обыкновенно не
полагают упорядоченными (перенумерованными), а элементу
массива всегда сопоставлен индекс.
Больше сходства у массива со словом в некотором
алфавите. В слове могут быть повторяющиеся буквы и
каждая буква имеет определенную позицию
(порядковый номер) в слове. Отличие здесь в том, что для работы
с массивом нужна арифметика — целые числа и какие-то
операции над ними. Знание индекса автоматически
обеспечивает знание значения элемента.
, Для работы со словом уже были введены и
многократно применялись операции, не использующие
арифметики.
Приведем алгоритм построения массива букв данного
слова т. Порядок букв будет сохранен.
М: Дано слово т. Используя операции голова, хвост
и отношение равенства между словами,
получить массив 1г, /2, ..., 1п букв слова т;
Ml: l: = l;
М2: пока "]т = « » выполнять
начало lt: = голова (т); т: = хвост (т);
" i: = i + l
конец
Задача 7. Написать алгоритм построения слова по массиву
его букв alt а2, .. ., ап.
§ 5. Алгоритм Евклида
1. Наибольшая общая мера двух отрезков. Как
построить с помощью циркуля и линейки наибольшую
общую меру двух соизмеримых отрезков?
Из двух отрезков выбираем наименьший и
проверяем, не укладывается ли он целое число раз в другом.
Если укладывается, то все закончено. Если не
укладывается, то можно рассмотреть половину выбранного
отрезка, а в случае неуспеха перейти к трети и т. д.
Условие соизмеримости отрезков гарантирует окончание
этого процесса. Мы описали простейший алгоритм.
Пусть нужно найти наибольшую общую меру
отрезков Л В и CD и |С0|<|Л5|. То, что будет происходить
на первом этапе, когда мы будем проверять, не
укладывается ли CD целое число раз в АВ, изображено на
62
рис. 24. Буквой Е с индексами обозначены точки,
возникающие при откладывании отрезка CD. Отрезок CD
не уложился в АВ целое число раз (получился отрезок-
остаток ЕгВ), надо переходить к исследованию
половины, трети, ... отрезка CD. Но любая целая доля
отрезка CD уложится от А до £4 целое число раз,
поэтому для проверки, укладывается ли она целое число
раз в отрезке АВ, ее можно-откладывать от £4 в
направлении В. Отсюда получаем, что наибольшая общая
мера отрезков АВ и CD равна наибольшей общей мере
отрезков £4В и CD. После того, как выяснилось, что CD
не укладывается целое число раз в А В и получилась
точка £4, начнем процесс поиска сначала, но будем
о о о . а о—-о 0 0 д 0
А 4 4 Е3 £* В с Л
Рис. 24. Рис. 25.
производить этот поиск применительно к отрезкам CD
и ЕйВ (нам ясно, что |CD|>|£4£|). Отрезок £4£ либо
уложится в CD целое число раз, и тогда он — искомая
наибольшая общая мера, либо не уложится, и мы вновь
перейдем к поиску наибольшей общей меры отрезка £4В
и некоторого меньшего отрезка (рис. 25).
Теорема. Для отыскания наибольшей общей
меры потребуется конечное число таких замен исходных
данных.
Если наибольшая общая мера отрезков АВ и CD
укладывается в меньшем отрезке CD m раз, то эта
наибольшая общая мера укладывается в
отрезке-остатке (в рассмотренном случае £4£) самое большое т—1
раз. Отсюда следует, что самое большое т—\ замена
исходных данных приведет к тому, что нужно
будет найти наибольшую общую меру двух отрезков,
меньший из которых целое число раз укладывается в
большем.
При переходе от пары отрезков к новой паре
больший отрезок из прежней пары можно забыть — он
больше не потребуется. Поэтому здесь не нужны
массивы. Нам пригодится алгоритм Л из § 3 (построение
точки, существование которой гарантируется аксиомой
непрерывности). Чтобы можно было применять алго-
63
ритм А, предварительно построим точку Е,
принадлежащую А В, такую, что AE=CD.
Я: Даны отрезки АВ и CD, \AB\^\CD\.
Построить отрезок с концами U и V—их
наибольшую общую меру;
HI: £:= П (В, А; А, С, D);
#2: повторять начало
С: =А(А, Е, В);
Л: = ПИ, В; С, А, £);
Е: =Б; В: =С
конец
пока не А — Е;
ЯЗ: U: = A\
Я4: V: = B
На рис. 26 изображен отрезок А В с точкой Е внутри
Над точками надписаны их начальные обозначения.
АС В
О Will ■ О ччи-м .1 И...1 ни I..I—и - ■ О О ■ ■ ■ i.iQ
А £ 3
Рис. 26.
Внизу приводятся обозначения, которые получат
некоторые точки после выполнения приказов С:—А (А, Е,
В); А:=() (А, В; С, А, Е); Е:=В\ В:=С.
То, что мы получили,— это алгоритм Евклида
нахождения наибольшей общей меры.
Оказывается, алгоритм Евклида обладает в
сравнении с алгоритмом, который обсуждался вначале,
существенным преимуществом: с его помощью
наибольшая общая мера двух отрезков будет построена
значительно быстрее.
Если наибольшая общая мера двух данных отрезков
укладывается т раз в меньшем отрезке, то применение
первого алгоритма естественно распадается на т этапов:
проверка, является ли сам меньший отрезок наибольшей
общей мерой, затем то же самое для половины
меньшего отрезка, трети и т. д., до Mm меньшего отрезка.
Алгоритм Евклида тоже распадается на некоторое число
однотипных этапов. Каждый этап состоит в построении
по двум отрезкам отрезка-остатка. Можно считать, что
если имеются два отрезка, то проверка укладывается
ли меньший целое число раз в большем и построение
отрезка-остатка — задачи одинаковой трудности. Ин-
64
тересно узнать, сколько этапов требует применение
алгоритма Евклида, если, первоначальный алгоритм
требует т этапов. Ответ на этот вопрос мы выведем из.
следующей теоремы.
Теорема. Пусть TU — отрезок-остаток,
построенный для отрезков PQ и RS (\PQ\>\RS\). Тогда
\TU\<\PQ\/2.
Доказательство. Для некоторого
натурального q имеем
\PQ\=q\RS\+\TU\^\PQ\+\TU\>2\TU\.
Теорема доказана.
Первый этап применения алгоритма Евклида к
отрезкам АВ и CD дает отрезок-остаток, по крайней мере
в 2 раза меньший отрезка АВ, третий этап — отрезок-
остаток, по крайней мере в 4 раза меньший АВ, и т. д.
Точно так же, второй этап дает отрезок-остаток, по
крайней мере в 2 раза меньший отрезка CD, четвертый
этап — отрезок-остаток, по крайней мере в 4 раза
меньший CD, и т. д. Через 2k этапов применения алгоритма
Евклида процесс или будет закончен, или будет
рассматриваться пара отрезков, меньший из которой короче
CD по крайней мере в 2k раз. В последнем случае
\CD\/2k>\CD\/m.n 2*<m. Пусть N—первое натуральное
число, для которого 2N~^m,— тогда A^^[log2m]+l.'
Следовательно число этапов, необходимых для
отыскания наибольшей общей меры отрезков АВ и CD, не
превзойдет 2([log2m]+l) и тем самым заведомо не
превзойдет 21og2m+2.
Мы получили сравнительную характеристику двух
алгоритмов нахождения наибольшей общей меры. Если
известно, что первый алгоритм требует ровно т этапов,
то можно быть уверенным, что второй алгоритм
потребует не более'21og2m+2 этапов. Это означает, что при
больших значениях т второй алгоритм — алгоритм
Евклида — существенно выгоднее первого. Графики
функций у=х и t/=21og2x+2 (рис. 27) наглядно
демонстрируют расхождение в числе этапов.
Если т=1000, то 2[log21000]+2=2-9+2=20: не более
двадцати этапов вместо тысячи.
Задача 1. Дать геометрическое доказательство
несоизмеримости отрезков, находящихся в среднем и крайнем отношении,
т. е. отрезков с длинами а и Ь, причем а>Ь и a/b=b/(a—Ь).
Указание. Если отрезки соизмеримы, то применим
алгоритм Евклида.
3 С. А. Абрамов
65
2. Наибольший общий делитель двух чисел. Если
задаться некоторым отрезком-масштабом и построить
отрезок в а раз более длинный, чем отрезок-масштаб
и еще один отрезок в Ь раз более длинный, чем отрезок-
масштаб, то наибольшая общая мера двух построенных
отрезков однозначно определит наибольший общий
делитель (НОД) натуральных чисел а и Ь.
Если имеется операция нахождения остатка от
деления, то в переходе от чисел к отрезкам нет никакой
необходимости. Сформулируем алгоритм Евклида для
чисел и дадим его
обоснование в арифметических
терминах.
Теорема. Для
любых а и Ь, сС^Ь>0,
выполнено НОД (а, 6)=НОД
(Ь, остаток (а, Ь)).
Доказательство.
Пусть а—qb+r, 0<><Ж
Тогда НОД (Ь, г) делит а
и, следовательно, делит
НОД (а, Ь). Из равенства
r~a—qb видно, что г
делится на НОД (а, Ь).
Отсюда НОД (Ь, г) делится
на НОД (а, Ь). Натуральные числа НОД (а, Ь) и НОД
(Ь, г) делят друг друга. Это означает, что они равны.
Теорема доказана.
Пусть йо и flj — натуральные числа, a0>ai. Поиск
НОД (а0, аг) по алгоритму Евклида требует выполнения
серии однотипных шагов, каждый из которых — деление
с остатком: '
Рис. 27.
а0
«1
а„.
"а»
а„.
= <?!«!
= 9 А
-з = 9я-
-i~Qn-
-1 = <7»а
+ а2.
+ а3,
гап-г
\ап-1
п'
+ а«-и
+ ап,
(1)
В этом случае ап=НОД (а0, а%), поскольку по
доказанной теореме НОД (я0, а^НОД (alf а2)=...=НОД
(а„, 0)=а„.
66
Так же, как было сделано в задаче отыскания
наибольшей общей меры, можно показать, что если 1^/^
<>г—1, то <^/2>а;+2 (считаем, что йп+1=0). Отсюда
следует, что количество делений с остатком в процессе
применения алгоритма Евклида не превзойдет 2[log2a1]+
+2^2\og2a1+2.
Задача 2. Доказать, что если d=HOR (a0, %), то число
делений с остатком не превзойдет 2Iog2(a/cf)-f 2.
Вот описание алгоритма Евклида:
Е: Даны натуральные а и b (a^b).
Найти й=НОД (а, Ь);
Е\: повторять
начало d: — остаток{а, Ь); а: — Ь; Ь: = d конец
пока не b = 0;
£2: d: = a
Для описания алгоритма Евклида, как теперь видно,
не нужны переменные с индексами. Последовательность
строчек (1), содержащая такие переменные, удобна для
изучения свойств этого алгоритма.
Задача 3. Как будет выполняться алгоритм, если условие
а>6 не соблюдено? Получится ли правильный ответ?
Задача 4. Доказать, что НОД(а0, а1)=ЫОЩа0—а1? aj).
Пользуясь этим соотношением, составить такой алгоритм нахожде-'
ния НОД, который вместо операции остаток использует операцию
вычитания и операцию отношения <.
Задача 5. а) Доказать, что для любых натуральных а и
Ь найдутся целые р и q такие, что apn-bq—HOR(a, b). Для
доказательства использовать строчки из последовательности (1), начиная
с предпоследней и продвигаясь снизу вверх, б) Решить в целых
числах уравнение 7х-\-\0у=Ь.
Задача 6. Дать алгоритм построения чисел р и q (см.
предыдущую задачу), не использующий переменных с индексами
(строчки из последовательности (1) перебираются сверху вниз).
3. Алгоритм Евклида для многочленов. Наибольшим общим
делителем двух многочленов f(x) и g(x) называется такой
многочлен d(x), который, во-первых, делит f(x) и g(x) без остатка и, во-
вторых, обладает тем свойством, что всякий многочлен, делящий
/(*) и g(*)> Делит и d(x).
Легко усмотреть, что таким способом можно было бы
определить и наибольший общий делитель двух натуральных чисел. Для
многочленов приходится пользоваться именно этим определением,
поскольку для них не определено отношение «больше».
Наибольший общий делитель двух многочленов если
существует, то определяется однозначно с точностью до числового
множителя: если d(x) и d!(х) удовлетворяют определению наибольшего
общего делителя многочленов f(x) и g(x), то они делят друг друга.
Следовательно, они имеют одинаковую степень и частное от деления
d(x) на d! (х) — многочлен нулевой степени, т. е. число. Если d(x) —
наибольший общий делитель }(х) и g(x), то, в соответствии с
3*
67
определением, для любого отличного от нуля числа с многочлен
cd(x) — тоже наибольший общий делитель f(x) и g(x).
Докажем существование наибольшего общего делителя двух
многочленов и одновременно рассмотрим способ его нахождения —
алгоритм Евклида. Известно, что для любых двух многочленов
/(*) и gWc рациональными или действительными коэффициентами,
таких, что g(x)^Q, однозначно определен остаток от деления f(x)
на g(x):
f(x)=q(x)g{x)+r(x),
где степень многочлена г(х) меньше степени многочлена g(x) или
г(х)=0.
Пусть }0(х) и ft(x) многочлены такие, что степень f0(x) больше
или равна степени fx(x). Можно по аналогии с (1) построить
последовательность остатков fi{x), /3(*)> U(x)< ■ ■ • Степени построенных
многочленов-остатков убывают. Рано или поздно встретится нулевой
многочлен (скажем, fn+i(x)) — последовательность оборвется.
Имеем, таким образом,
/oW =?i(*)M*)+M*).
fAx) = <М*)М*) + М*).
fa-Ax) = q«-t(x)fn-t(x) + In-i(x), ^>
f»-t (x)=*q„-i {x) /„_, (x) -\- fn (x),
* fn-i(x) = q„(x)fn{x).
Из цепочки равенств (2) следует, что fn(x) делит fn-i (x),
/j-i(4 ••'■. /jW> /i W, /oW- Значит, /„(*) удовлетворяет
первой части определения наибольшего общего делителя /0 (х), ji(x).
£сли теперь d (х) делит /0 (■*) и /х (лг), то, двигаясь от первой
строчки к предпоследней, убеждаемся, что d(x) делит /2(*).
fs(x) /n-i(*)i /n W> и тем самым удовлетворена вторая часть
определения.
3 а д'а ч а 7. Найти наибольший общий делитель
многочленов
х4 + 2*3 + 3x2 + 2x+l и хз+ 1 ад! х_ ' _
Задача 8. Доказать, что если многочлены f(x) и g(x) с
рациональными коэффициентами не имеют общего делителя среди
многочленов ненулевой степени с рациональными коэффициентами,
то они не имеют общего делителя и среди многочленов ненулевой
степени с действительными коэффициентами.
Указание. Если общий делитель существует, то он делит
наибольший общий делитель, который может быть найден по
алгоритму Евклида и поэтому имеет рациональные коэффициенты.
Попытка перенести алгоритм Евклида на многочлены от
нескольких неизвестных (например, на многочлены от неизвестных х,
у) не приводит к успеху. Для таких многочленов невозможно
определить деление с остатком так, чтобы в последовательности
остатков, получаемых с помощью алгоритма Евклида, обязательно встре-
68
чался нулевой остаток. Если бы наибольший общий делитель
многочленов f(x, у) и g(x, у) мог быть найден последовательными
нахождениями остатков, то (см. задачу 5) существовали бы и многочлены
р(х, у) uq(x, у) такие, что р(х, у)}(х, y)+q(x, y)g(x, </)=НОД(/(х, у),
g(x, у)). Возьмем f(x,y) = x, g(x, </)=</. Очевидно, что наибольший
общий делитель этих многочленов — это любое не равное нулю
число с, например 1. Однако равенство р(х, y)x-\-q(x, у)у= 1
невозможно ни при каких р(х, у) и q(x, у), так как свободный член левой
части равен нулю.
Вместе с тем для любых двух ненулевых многочленов от
нескольких неизвестных с действительными или рациональными
коэффициентами наибольший общий делитель существует. Известны
алгоритмы его нахождения.
Глава III. РЕКУРСИЯ
Иногда оказывается удобным свести задачу к
другой, более простой задаче, а иногда — свести задачу
к ней же самой, упростив исходные данные. Последнее
будет подробно обсуждено в этой главе.
§ 1. Упрощение исходных данных
Пусть известно, как решать задачу для простейших
исходных данных и как сводить ее к более простым
исходным данным во всех остальных случаях. Если
несколько последовательных этапов упрощения наверняка
приводят задачу к известному простому случаю, то
можно считать, что получено полное решение задачи.
Рассмотрим, например, как вычисляется значение выражения.
Если выражение — переменная, то берется ее значение. Если же
выражение состоит из нескольких других выражений, связанных
знаком некоторой операции, то надо вычислить значения этих
выражений (более коротких) и к ним применить операцию.
Способ сведения задачи к ней же самой, но с
измененными исходными данными, называется рекурсией.
Алгоритм решения задачи, который содержит обращения
к себе, называется рекурсивным алгоритмом.
1. Нахождение наибольшей общей меры. Алгоритм
Евклида нахождения наибольшей общей меры двух
соизмеримых отрезков А В и CD (\AB\^\CD\) может быть
кратко сформулирован следующим образом: укладываем
CD и АВ максимально возможное число раз и находим
отрезок-остаток EF; если отрезок-остаток нулевой, то
наибольшая общая мера АВ и CD равна отрезку CD,
иначе она равна наибольшей общей мере CD и EF.
Получено словесное описание рекурсивного варианта
алгоритма Евклида: оговорен некоторый простой случай
70
(отрезок-остаток — нулевой) и показано, как во всех
прочих случаях сводить дело к новым данным. В § 5
доказывалось, что несколько таких этапов замены
данных приводят к этому простому случаю.
Алгоритм можно записать, например, так:
#': Даны отрезки АВ и CD (\CD\^\AB\).
Построить UV — их наибольшую общую меру;
Н'\: построить отрезок-остаток с концами Е и F;
Н'2: если (Е; F) то. начало U:=C; V:=D; выход конец;
Н'З: построить U и V с помощью Н', примененного
к CD и EF
Алгоритм Н' содержит два обращения к алгоритмам.
Первое — к алгоритму построения отрезка-остатка, этот
алгоритм можно получить, например, путем некоторых
переделок алгоритма А (§ 3 гл. II). Второе —
рекурсивное обращение. Каждый из алгоритмов предназначен
для построения двух объектов (точек), поэтому
обращения к ним нельзя записывать в виде функции или
операции, в рамках нашего способа записи алгоритмов
приходится давать словесные пояснения.
Задача 1. Составить рекурсивный алгоритм построения
отрезка-остатка.
2. Передвижение шашки. Рекурсии часто возникают
при решении комбинаторных задач. Пример: имеется
полоска клетчатой бумаги шириной в одну клетку и
длиной в п клеток. На первой клетке установлена шашка.
Одним ходом шашку можно продвигать вперед на одну
или две клетки. Сколько существует способов
продвижения шашки на п-ю клетку? Будем называть способ
продвижения маршрутом и обозначим число маршрутов
с 1-й на п-ю клетку и(п). При небольших п значения
и(п) вычисляются непосредственно:
н(1)=1: единственный маршрут — оставаться на
месте;
ы(2) —1: единственный маршрут — ход на одну
клетку;
и(3)=2: один маршрут — ход на две клетки и еще
один — два хода на одну клетку;
и(4)=3: если ход обозначить буквой о (одна клетка)
или g (две клетки), то имеем маршруты
ооо, og, go.
Дальше подсчет усложняется, хотя еще не слишком
трудно убедиться, что ы(5)=5.
71
Глядя на первые значения 1, 1, 2, 3, 5, непросто
сообразить, какова формула или хотя бы каков алгоритм
вычисления и (п). Если попробовать применить
рекурсию, дело проясняется. При я>2 любой маршрут,
ведущий на п-ю клетку, кончается одним из двух
возможных ходов. Если последний ход откинуть, то
получится маршрут, который ведет либо на (п—1)-ю клетку,
либо на (п—2)-ю. Поскольку множества маршрутов,
ведущих на n-ю клетку и приводящих предпоследним
ходом на (п—1)-ю и (п—2)-ю клетки, не пересекаются,
имеем
и(п)=и(п—1)+и(п—2). (1)
Полученная формула определяет необходимое для
рекурсии упрощение исходных данных. Вместо одной
задачи можно решить две менее сложные. Необходимо
еще выделить ряд простых случаев, к которым в
конечном итоге задача сводится с помощью (1). Самый простой
случай — и=1, и(1)=1. Но ограничиться лишь этим
простым случаем нельзя: попытка вычислить и (2)
приведет к необходимости вычислить u(l)+u(0), a u(0)
смысла не имеет. С другой стороны, если известны и(1),
ы(2), то формула (1) доопределяет и для всех
натуральных п. Итак, возможен рекурсивный алгоритм:
и: Дано п. Вычислить /, равное и(п), которое
задано формулой (1) и равенствами ы(1)=и(2)==1;
ul: если n=\\Jii=2 то начало /: = 1; выход конец;
и.2: f:=u(n—l)+u(n—2)
Шаг ы2 содержит два рекурсивных обращения.
Результат применения алгоритма и — это одно число.
Поэтому оказалось возможным записать обращение к
нему в виде функции или операции.
Элементы последовательности, удовлетворяющей
условию
ы(1)=и(2)=1, и{п)=и(п— 1)+и{п—2),
называются числами Фибоначчи. Числа Фибоначчи
играют видную роль во многих математических теориях.
Они получили свое название в честь итальянского
математика XIII века Фибоначчи, который рвел их для
описания численности поколений размножающихся
кроликов (без учета смертности).
72
Задача 2. Вычислить и(6), и(7), . . ., «(10).
Задача 3. Составить алгоритм вычисления и(п) без
рекурсии. Организовать последовательное (циклическое) вычисление
значений «(3), и (4), . . ., и(п). Массив здесь не нужен: достаточно
в каждый момент помнить два последних вычисленных значения.
Задача 4. Составить рекурсивный и нерекурсивный
алгоритмы вычисления значения р(п): р(1)=1, р (п)= пр (п— 1).
Доказать, что р(п)=п\
Соотношения типа (1) называются рекуррентными
соотношениями. Слова «рекурсивный» и «рекуррентный»
имеют общий смысл, они происходят от латинского
recurro — бежать назад, возвращаться. Рекуррентное
соотношение в общем случае может быть записано в виде
v (n)=F (n, v (п-1), v (п-2), ..., v (n-k)), (2)
где F — некоторая функция /г+1 аргумента. Число k
называется порядком соотношения. Так, соотношение
(1) имеет порядок 2, соотношение р(п)—пр(п—1) —
порядок 1. С помощью (2) можно вычислять значения
у (п) для натуральных n>k, если известны k начальных
значений v(l), v(2), ..., v(k).
Задача 5. В задаче о продвижении шашки выписать
рекуррентное соотношение и начальные условия для числа маршрутов
в предположении, что:
1) допустимые ходы — ходы на одну, две и три клетки вперед;
2) допустимые ходы — ходы на одну и четыре клетки вперед.
3. Построение всех маршрутов. Рассмотрим задачу
построения всех маршрутов шашки. Каждый маршрут
может быть изображен словом в алфавите {о, g}: о —
это ход на одну клетку вперед, g — на две.
Совокупность маршрутов можно представить словом
определенного вида в алфавите {о, g, <>}, буква <> играет роль
разделителя слов-маршрутов. Как уже говорилось,
множество всех маршрутов для п>2 распадается на два
непересекающихся подмножества: первое образуют
маршруты с последним ходом о, второе — с последним ходом
g". Можно рекурсивным обращением построить
совокупности маршрутов для п—1 и п—2, а затем слить эти
совокупности, добавив к каждому маршруту первой
совокупности ход о, а к каждому маршруту второй
совокупности — ход g. Будем предполагать, что в нашем
распоряжении имеются операции над словами голова.
73
хвост, °, =. В качестве наброска алгоритма можно
рассмотреть следующее:
1/1: если п=1 то начало М:=« »; выход конец;
U2: если п = 2 то начало Л1: = «о»; выход конец;
U3: K: = U(n—\)\
U4: L:=U(n~2);
Ub: M:*=« »;
1/6: пока ~| л* = « » выполнять
отщепить первый маршрут от К,
добавить к нему (в конец) о
и приписать получившееся к М;
VI: /гока~|1 = «» выполнять
отщепить первый маршрут omL,
добавить к нему (в конец) g
и приписать получившееся к М
Если при выполнении шага U6 К имеет в какой-то
момент значение o^aj.. .as<>|3iP2.. .Pf-C-TiYs-.., а М
в свою очередь имеет значение б1б2.. .бц^е^г..., то
можно присвоить значение ocxcx.... .as некоторой
дополнительной переменной р, а значение Д" превратить в
Pi^2- - .Pt<>7iV2- • • • После этого М превращается в
o<>6i62.. .6„<>eie2... и слово р сцепляется с М. В конце
этого процесса К. примет значение p\pY . .p\<>YiY2..., М
примет значение о^оц.. .aso<>6i62.. .бц^е^г...
Переменная р привлечена по той причине, что мы хотим
сохранить в М тот же порядок следования букв а1;
а2, ..., ав, какой они имели в слове К,- Можно, однако,
пойти на то, чтобы этот порядок менялся на обратный.
В самом деле, в полной совокупности маршрутов наряду
с маршрутом, изображенным словом a1a2.. .ag, есть
маршрут, который изображается словом as.. .aja^ Это
дает возможность сократить число операций: сразу
присваиваем М в качестве значения букву о, а затем
присоединяем к М букву за буквой содержимое К, при
этом вслед за каждой буквой <0> присоединяем букву о.
Таким же образом поступаем с L, только вместо о
вставляем g:
U: Дано п. Необходимо построить М —
совокупность всех маршрутов движения шашки с 1-й
клетки на п-ю;
U\: если п=\ то начало М:=« »; выход конец;
/72: если п=2 то начало М:=«о»; выход конец;
U3: K: = U(n~l);
UA: L: = U(n~2);
74
f/5: M:=«o»;
£/6: пока "]/( = « » выполнять
начало t: — голова (/С);
К: = хвост (К); M: = "(t, M);
если t = «о» то М: = " («о», М)
конец;
U7A: M: = "(«g», «<>», М);
U7.2: пока ~] L = « » выполнять
начало t:= голова (L);
L: = хвост (L); M:=u(/, M); .
еслы £ = <«>» то УИ: = u («g», M)
/соке^
Задача 6. Шаги С/6 и £/7.2 текстуально почти совпадают -^
имеет смысл составить алгоритм решения нужной подзадачи.
Составить этот алгоритм с использованием рекурсии и без приказа
цикла.
Задача 7. Переделать алгоритм U так, чтобы он не содержал
рекурсий.
Указание. Совокупности маршрутов для я=1 и я=2
выписать несложно. Далее можно последовательно (циклически)
найти совокупности для 3, 4 п.
§ 2. Рекуррентные соотношения
Определение рекуррентного соотношения порядка k
дано в предыдущем параграфе. Такие соотношения
интересны тем, что часто позволяют просто и быстро решать
комбинаторные задачи. Рекуррентные соотношения
полезны и при анализе рекурсивных алгоритмов, поэтому
займемся ими подробнее.
1. Решение рекуррентного соотношения. Если
задано рекуррентное соотношение порядка k
f(n)=F(n, /(n-1), ..., f(n-k)), (l)
то произвольный набор из k чисел а, Ь, ..., t однозначно
определяет для п>0 некоторую функцию
(последовательность), удовлетворяющую (1), для которой f(\)=a,
f{2)=b, ..., f(k)=t. В самом деле, зная /(1), /(2), ...
..., / (k), мы можем по формуле (1) однозначно определить
/(/г+1); зная /(2), /(3), ..., /(/г+1) — однозначно
определить /(/г+2) и т. д. Взяв другие начальные
условия, мы получим тем же способом другую функцию
от п, удовлетворяющую (1). Каждая такая функция
называется решением рекуррентного соотношения (1).
75
Решениями соотношения порядка 1
р(п)—пр(п—1)
являются, в частности, я! и 7л!. Решениями соотношения
f(n)--f(n—2) будут, в частности, тождественный нуль
и остаток от деления п на 2.
Общее решение соотношения (1) — это такая функция
U (сг, с2, ..., cft, л) от k+l переменной си с2, ■ •., ch, n,
что:
1° при подстановке в U любых чисел вместо сг, с2,
..., ch получается решение (1);
2° для любого решения f(n) соотношения (1) можно
подобрать такие значения си'с2, ..., ск, что при
подстановке этих значений в V получается функция от. я,
тождественно равная f(n).
Например, общее решение соотношения f(ri)=nf(n—1)
есть Суп\, так как при любом сг
с1п\=п-с1(п—1)!
и любое решение f(n) получается из C\ti\ подстановкой
/(1) вместо d.
Общее решение соотношения f(n)—f(n—2) есть сх-\-
+с2(—1)" — при любых сь сг соотношение
удовлетворяется тождественно, и по произвольным начальным
значениям f{\), /(2) мы определяем d и с2 так, чтобы
й+с, (-1)=/ (1), d+c2 (-1)*-/ (2):
/(!) + /(2) _/(2)-/(1)
Ч — 2 » 62 — 2
Задача I. Найти общее решение рекуррентного соотношения
f(n)=af(n—1), где а— некоторое отличное от нуля число. Найти
решения, удовлетворяющие условиям:
а) /(l)=fl.
б) f(l)=0.
2. Линейные однородные рекуррентные
соотношения с постоянными коэффициентами. Рекуррентное
соотношение
f(n)=a1f(n—l)+aj(n-2)+...+allf(n—k), (2)
где аи а2, ..., ah — некоторые числа, называется
линейным однородным рекуррентным соотношением с
постоянными коэффициентами.
76
Примеры линейных однрродных рекуррентных
соотношений с постоянными коэффициентами:
/(л) = /(л-1) + 2/(п-2)+3/(п-3),
/(п) = /(я-1) + /(п-2),
/(л) = /(л-2),
/(") = -/("-!)•
Порядок рекуррентного соотношения (2) равен k, коль
скоро акф\). Выписанные примеры представляют собой
соотношения порядка 3, 2, 2, 1.
Следующие соотношения не являются линейными однородными
рекуррентными соотношениями с постоянными коэффициентами:
f(«) = P(n-l) + sin(/(«-2)),
/(л) = /(л-1) + 3,
/(я) = я/(я—1).
Первое из соотношений можно назвать нелинейным, второе —
линейным неоднородным рекуррентным соотношением с
постоянными коэффициентами, третье — линейным рекуррентным
соотношением с переменными коэффициентами.
Цель этого пункта — вывод общего решения
однородных линейных рекуррентных соотношений с
постоянными коэффициентами порядков 1 и 2. Это те
соотношения, которые будут использоваться нами в
дальнейшем.
Свяжем с соотношением (2) алгебраическое уравнение
которое будем называть характеристическим
уравнением соотношения (2). Для соотношения порядка 2
f(n)=a1f(n-- l)+aj{n—2), афО (3)
характеристическое уравнение представляет собой №=
=ai%-\-a2. Для соотношения порядка 1
f(n)=af(n—l), а^О (4)
характеристическое уравнение представляет собой %=а.
Теорема. Если Яь Я2 — корни
характеристического уравнения соотношения (3), такие, что %хфХ%,
то общим решением этого соотношения будет сД?+с2Х";
если к1=Х2, то общим решением будет (ci.-\-cin)'k1.
Доказательство основывается на леммах.
Лемма 1. Если fi(n), f2(n) — решения
соотношения (3), и аь а2 — некоторые числа, то «i/i (я)+
+аг/2 («) — решение соотношения (3).
77
Доказательство. Из того, что U(п), /2(я) —
решения соотношения (3), получаем
h (n)=aifi (n— \)+aJx (я—2),
ft (n)=a1/-s (n— l)+a2/2 (/г—2).
Домножим первое равенство на аь а второе — на сс2
и почленно сложим результаты. Получим
aifi(n)+a2f2(n)=
=«itotifi (n— \)+ct2fа (n—^l+ajax/j (r—2)+a2/2 (n—2.)],
что полностью доказывает лемму.
Лемма 2. Пусть К — корень алгебраического
уравнения, являющегося характеристическим для
соотношения (3). Тогда %" — решение соотношения (3).
Доказательство. Нужно показать, что
X" = a^"-i + a2?vn-2 при п>2.
Это то же самое, что показать
lkn-~aiX"->-—ai'k"-i = 0.
Имеем
V1 — аД""1—а2Хп-2 = А,"~2(Ха—а^—а2) = 0.
Лемма 3. Пусть характеристическое уравнение для
соотношения (3) имеет кратный корень %i. Тогда nkl—
решение соотношения (3).
Доказательство. Если X2—atX—а2=0 имеет
кратный корень4 Ки то ai=2^i, a2=—Я2. Следовательно,
(3) можем переписать в виде
f (п)=2^ (п— 1)—ХУ (п—2).
Подставляем в полученное соотношение /(и)=и^ и
переносим все в левую часть:
лЯ£ — 2A,j (n—1) Xf^ + XKn—2) ЯГ2 =
= Х,?[п—2(n— 1) + п—2]=Х?.0 = 0,
что и требовалось доказать.
Из лемм 1, 2 следует, что при различных корнях
Ki, Кй характеристического уравнения функция сД?-4-
+сД" является решением соотношения (3) для любых
Си сг. Из лемм 1, 2, 3 следует, что при наличии у
характеристического уравнения кратного корня К± функция
Cxi.'l+crfik'l является решением соотношения (3),
какими бы ни были числа си сг. Для завершения доказа-
78
тельства теоремы нужно показать, что любое решение
соотношения (3) может быть получено подстановкой
некоторых чисел в CiX1-\-c2nX1 или сД"+с2Я£ в
зависимости от того, имеет или нет характеристическое
уравнение кратные корни.
Пусть характеристическое уравнение имеет простые
корни Xi, X2, и пусть f(n) — некоторое решение
соотношения (3). Известно, что f(n) однозначно определяется
значениями /(1), /(2). Докажем, что сх и с2 могут быть
подобраны так, что
Clkl-\-ctkl=f(2).
Полученная система линейных алгебраических
уравнений относительно сь с2 имеет единственное решение,
так как ее определитель XJ4 — X^X\--=--XLX2 (Хг—Х2)
отличен от 0.
Пусть теперь характеристическое уравнение имеет
кратный корень ?ц. Тогда сь с2 аналогично
предыдущему можно определять из системы
сА+сА =/(1),
,сА! + с,-2.А,! = /(2).
Определитель этой системы 2Х\—Х\=Х\ отличен от
нуля (так как агф$), следовательно, система имеет
единственное решение.
Задача 2. Доказать, что общее решение линейного
однородного рекуррентного соотношения с постоянными коэффициентами
(4) порядка 1 есть сап.
Выведем формулу для я-го числа Фибоначчи.
Рекуррентное соотношение для чисел Фибоначчи имеет
видц(я)=ц(п—1)+и(я—2), начальные условия— и(1)=
—ы(2)=1. Характеристическое уравнение этого
соотношения А,2=--М-1 имеет корни
. I ••!- ]/"5 . 1— |/"5
A-! = 2 ' Л* = Г-'
Отсюда заключаем, что общее решение изучаемого
рекуррентного соотношения представляет собой
79
Используя начальные условия, составляем систему
уравнений для определения си с2:
Ее решение
_ l \_
- Ci " VI' °1 ~~ \П>'
Теперь можно написать
■»<.)-u(№)--N2)-)- <5>
Следует помнить, что и (п) при любом п целое число.
Задача 3. Бесконечная последовательность образована
следующим образом: первый ее член равен единице, второй — двум.
Каждый член, начиная с третьего, равен среднему арифметическому
двух предыдущих членов. Доказать, что полученная
последовательность стремится к некоторому пределу, и найти этот предел.
3. Линейные неоднородные рекуррентные
соотношения с постоянными коэффициентами.
Рекуррентное соотношение
f(n)=aj(n—\)+aj{n—2)+.. .+akf(n~k)+v(n), (6)
где аи ..., ak — некоторые числа, a v(n) — данная
функция от п, не равная тождественно нулю, называется
линейным неоднородным рекуррентным соотношением с
постоянными коэффициентами.
Теорем а. Общее решение соотношения (6) может
быть представлено как сумма общего решения линейного
однородного соотношения с постоянными
коэффициентами
f(n)=aif(n-l)+a,f(n-2)+.. .+akf(n-k) (7)
и какого-нибудь решения соотношения (6).
Доказательство. Пусть U (сь с2, ..., ch, n)
общее решение соотношения (7). Пусть d(n) — одно
из решений соотношения (6). Первое, что нужно
показать — это то, что для любых k чисел а, Ь, ..., s функ-
80
ция U (а, Ь, ...-, s, n)+d(n) представляет собой решение
соотношения (6). Имеем
[U (а, Ь, ..., s, n)+d(n)] — ai[U (а, Ь, ..., s, n— \) +
+d{n— 1)]—...— ak[V (a, b, ...,s, n—k)+d(n—k)]—v(n)=
~[U (a, b, ..., s, n)-a^U (a, b, ..., s, n — 1)—...
... — ahU (a, b, ..., s, n—k)] + \d(n)—axd(n—1)—...
.. .— akd(n — ft)—u(re)] = 0 + 0 = 0.
Теперь осталось показать, что если w(n)
удовлетворяет соотношению (6),- то можно подобрать такие k
чисел а, р\ ..., а, что
w(n) — U(a, р, ..., о, n)+d(n).
Рассмотрим функцию w(n)—d{n). Имеем
w(n)—aiw(n—1)+.. .+ahw(n—k)+v(n),
d(n)=a1d(/z—1)+.. .+ahd (n—k)+v (n);
отсюда
[w(n)~ d(n)]=
■ = a! [w (n— I)—d (n— 1) ]+...+ah \w {n—k)—d (n—k) 1".
Таким образом, w(n)—d(n) удовлетворяет (7) и,
следовательно, может быть получена из. U (ci, ..., Ck, «)
подстановкой некоторых значений а, {$, ..., а вместо
Си ..., ch. Получается, что
w(n)=U(a, р\ .... a, n)+d{n).
Теорема доказана.
Пусть, например, нас интересует общее решение
соотношения
l(n)=l(n-l)+l(n-2)+l.
Легко убедиться, что одним из решений этого
соотношения является функция, тождественно равная —1.
Общее решение соотношения £(«)=£ (я—1)+£(я—2) нам
известно из примера предыдущего пункта. Составляя
сумму, получаем общее решение обсуждаемого
неоднородного соотношения
При достаточном навыке подбор каких-то решений
линейных неоднородных рекуррентных соотношений с
81
постоянными коэффициентами первого и второго
порядков — дело не очень сложное. В дальнейшем всякий
раз, когда потребуется такой подбор, решение будет
выписываться и при этом не будет указываться, каким
именно образом оно было подобрано. Однако если у
читателя возникнет необходимость в самостоятельном
решении линейных неоднородных рекуррентных
соотношений с постоянными коэффициентами, то оказывается
полезным рецепт, основанный на теореме, приводимой
здесь без доказательства.
Теорема. Пусть в соотношении (6) v(n)=q(n)\i",
где q (п) — многочлен от п степени I, а ц — s-кратный
корень характеристического уравнения kk=a1kk-1-\-...
...+%. Тогда существует решение соотношения (Б),
имеющее вид р (п)|л", где р (п) — многочлен от п степени не
выше /+s.
Напомним, что (д. называется s-кратным корнем
многочлена г (к), если г (к) делится на (>—-И-)5 и не делится
на (к—цУ+1- В частности, если г(\х)Ф0, то \i — это
0-кратный корень.
В соотношении £(п)=|(л—1)+?(«—2)+1 роль v(n) играет
функция, тождественно равная 1. Можно считать, что эта функция
тождественно равна 1™, и даже(?(я)-1", rjifiq(n)=l. Число 1 является
0-кратным корнем характеристического уравнения, следовательно,
должно существовать решение в виде р(п)\", где р(п) — многочлен
от п нулевой степени, т. е. в виде а\п=а. Подставляя а вместо |(«),
получаем, что должно быть выполнено
а=а+а-|-1,
откуда а=—1.
Задача 4. Найти общее решение соотношения
Ч (»)= — Ч («— 1)+ л (— 1)" •
§ 3. Анализ рекурсивных алгоритмов
Вернемся к алгоритмам, рассмотренным в § 1.
Выясним, какое число операций требует выполнения этих
алгоритмов.
1. Сравнение алгоритмов Н и //'. Цель этого пункта —
установить, что число построений отрезков-остатков,
требуемое алгоритмом Н', совпадает с числом
построений, требуемым алгоритмом Н (§ 5 гл. II).
Для двух соизмеримых отрезков АВ и CD таких,
что |ЛБК|СО|, было доказано
НОМ(ЛВ, CZ)) = HOM(CD, EF). (1)
82
Здесь НОМ означает наибольшую общую меру, a EF
отрезок-остаток, получающийся после того, как CD
уложен в АВ максимально возможное число раз.
Алгоритм Н' использует соотношение (1) в явном
виде: на этом равенстве построена рекурсия. Алгоритм
Н требует последовательного (циклического) построения
остатков.
Доказательство высказанного утверждения приведем
индукцией по числу п построений отрезков-остатков,
требуемых алгоритмом Н.
Г Пусть п=1. Это означает, что второй отрезок
целое число раз укладывается в первом отрезке АВ.
Применяя алгоритм Н' к такого рода исходным данным,
видим, что выполняется одно нахождение
отрезка-остатка (шаг Я'1), а затем (шаг Н'2) два присваивания и
приказ выход. Итак, будет произведено одно построение
отрезка-остатка.
2° Пусть утверждение верно для п=1, 2, ..., k.
Докажем, что оно верно и для n=k+\. После первого
построения отрезка-остатка алгоритм требует
выполнения некоторых присваиваний (шаг #2). После этих
присваиваний, ввиду равенства (1), построений отрезков-
остатков потребуется столько же, сколько их
потребовалось бы, если б алгоритм Н применялся с самого
начала к отрезкам CD и EF. Это число равно k. По
предположению индукции, число построений отрезков-
остатков, требуемых Н', тоже равно k. Отсюда число
построений для отрезков АВ и CD будет равно k+l.
Что и требовалось доказать.
2. Вычисление с помощью рекуррентного
соотношения. Пусть имеется рекуррентное соотношение второго
порядка
f(n)=F(f{n-l), f(n-2)),
f(l) = a, /(2) = &. {>
Нерекурсивный алгоритм вычисления f(n) с помощью
соотношения (2) предполагает рассмотрение значений
/(1), /(2), /(3) /(/г), где /(1), /(2) даны, а дальше
каждое значение вычисляется по двум предыдущим.
Это может быть сделано, например, так:
/: Нерекурсивное вычисление d=f(n). Функция f(n)
определена условием (2);
/1: если п=1 то начало d:=a; выход конец;
/2: если п=2 то начало d:=b; выход конец;
83
/3: j:=2;
/4: d: = b;
/5: e:=a;
/6: повторять начало u:=d\ d: = F(d, e)\
e: = u; i: ■■i-\~\
конец
пока не i—n
Ясно, что при п>2 этот алгоритм требует п—2
вычисления значений функции F.
Теперь вернемся к рекурсивному способу
вычисления. Мы не будем составлять алгоритм, поскольку он
мало отличался бы от алгоритма и из § 1- (вместо
операции сложения в w2 нужно применить функцию F
и изменить в и\ начальные условия). Выясним, сколько
вычислений функции F потребуется при нахождении
значения f(n), если вычисление производится по
алгоритму, который содержит рекурсивные обращения,
определяемые формулой (2). Пусть это количество
вычислений есть £ {п). Проследим, из чего складывается % (п):
нужно найти f(n—1) и f(n—2) — это потребует %(п—1)
и соответственно | (я—2) вычислений значений функции
F, затем нужно вычислить F(f(n—l), f(n—2)) — это
потребует еще одного вычисления F. Получается
рекуррентное соотношение
l(n)==t(n—\)+l(n-2)+l. (3)
Если п—\ или п=2, то вычислять F не требуется,
следовательно |(1)=|(2)=0.
Нам уже известно общее решение рекуррентного
неоднородного соотношения (3) с постоянными
коэффициентами (см. пример из п. 3 § 2):
Подбираем. С\ и с2 так, чтобы удовлетворить начальным
условиям. Получаем
т.е. \{п)=и{п)—1, где и(п) — п-е число Фибоначчи.
Для п из промежутка от 1 до 10 значения £(л) суть
0, 0, 1, 2, 4, 7, 12, 20, 33, 54.
84
с осно-
Для нерекурсивного алгоритма количество
вычислений функции F есть п—2 и первые 10 значений выглядят
так:
0, 0, 1, 2, 3, 4, 5, 6, 7, 8.
Прежде чем устанавливать причину расхождения,
исследуем характер роста функции с(п). Слагаемое
1 /1+J/1Y'
-j=.! —j— I есть произведение положительного числа
l/j/"5 на показательную функцию ( "J—J
ванием > 1, так как ^5>1. Более точные
вычисления показывают, в частности, что
1,6180 < 1+2^5< 1,6181.
Поэтому первое слагаемое растет как показательная
функция с основанием, большим единицы. Второе сла-
1 /i_iA5\"
гаемое у= I—~—I характеризуется тем, что его
абсолютная величина стремится к„0 при п—юо.Это
1— VI,
происходит потому, что
2
< 1, а более точно:
—0.618К1 /~^<— 0,6180.
Таким образом, получается, что для больших
п1(п)ж——( ~г —J —1. Сопоставление графиков
1 Л-1- V~5\x
функций -7= (—'-%■—) —1 и х — 2 (рис. 28) не
оставляет сомнения в практических преимуществах
нерекурсивного алгоритма перед рекурсивным (имеются
в виду рассмотренные варианты алгоритмов).
Задача 1. Доказать, что отношение длин двух отрезков,
находящихся в среднем и крайнем отношении (см. задачу 1 §5
гл. II) есть (1+ f5)/2.
То, что рекурсивный алгоритм требует лишних
вычислений функции F, объясняется следующим образом.
Вычисление /(я) требует вычисления f(n—1) и f(n—2),
a f(n—1) в свою очередь потребует вычисления f(n—2)
и f(n—3). Таким образом, даже не прослеживая хода
85
вычислений слишком далеко, мы видим, что требуются
два независимых вычисления f{n—2), при этом
вычисление f(n—2) по тем же причинам будет выполняться
не лучшим образом.
Теперь понятно, что если требуется составить
алгоритм, применимый к натуральному п, то нецелесообразно
включать в него рекурсивные обращения и со значением
аргумента п—1, и со значением аргумента п—2.
Разумеется виной всему не сама рекурсия, а неудачное ее
применение.
Циклическое вычисление тоже
1 //+V5~\X может быть организова-
' но так, что будут
повторяться уже
проделанные вычисления.
Однако коварство
рекурсии проявляется в том,
что бывает довольно
трудно заметить дефект,
а в циклическом
процессе все на виду.
В завершение
выясним, как можно разумно
устроить рекурсивный
алгоритм вычисления
функции /(«),
заданной рекуррентным
соотношением (2).
Хотелось бы устроить алгоритм так, чтобы он содержал только
одно рекурсивное обращение, скажем со значением
аргумента п—1. Это можно сделать, если пойти на то, что в
результате применения алгоритма будет вычисляться
пара значений /(/г) и f{n—1), а не одно значение /(/г),
как прежде:
Рис
</(«), f(n-l)> =
<F(f(n-\), f(n-2)), f{n-
<b, a>, если » = 2.
1)>, если п > 2,
Получилось в некотором смысле нечто сходное с
алгоритмом Евклида: переходим от пары к паре, при этом
один элемент старой пары переходит в новую пару без
перевычисления.
Алгоритм будет иметь вид:
/': Дано я>2. Вычислить d—f(n), e—f(n—1) (см. (2))
пользуясь рекурсиями;
f'l: если п=2 то начало d:=b, e:=--a конец;
/'2: вычислить d и е по алгоритму f для п—1;
/'3: u:^F(d, e);
f 4: e:=d;
/'5: d:=u
Здесь рекурсивное обращение — па шаге /'2.
Алгоритм предназначен для вычисления двух значений и
не может быть использован как функция, поэтому
пришлось включить словесные объяснения.
Найдем количество вычислений значений функции F
в этом алгоритме. Обозначим его т] (п).
Для п>2 имеем:
(f(n), f(n-l))=(F(f(n-l), f(n-2)), f(n~\)).
На определение пары значений (f(n—1), f(n—2)) уйдет
ц(п—1) вычислений функции F и еще одно
вычисление — для нахождения первого элемента новой пары.
Отсюда
ч\(п)=ц(п—1)4-1.
Начальное условие т)(2)=0, так как при п==2 сразу
выдается пара {Ь, а).
Общее решение соотношения ц(п)=ц(п—1) есть С\п
или просто С. Нетрудно убедиться, что п является
решением соотношения ц(п)—х\(п—1)4-1. Поэтому общее
решение соотношения ц(п)=л\(п—1)4-1 есть С+п.
Подбираем С так, чтобы удовлетворить начальному условию
т](2)'—0, получаем С=—2, ц(п)=п—2. Количество
вычислений функции F такое же, как при использовании
нерекурсивного алгоритма.
Задача 2. Переписать алгоритм и (см. § I, п. 2), сохранив
его рекурсивность, но исключив перевычисления.
Задача 3. Составить нерекурсивный и рекурсивный
алгоритмы вычисления значения функции g(n), заданной рекуррентным
соотношением
g(n)=G(g(«-l), g(n-2), g(n-3))f
g(\)~p, g(2)=q, g(3)=r. Показать, что если организовать
рекурсию, непосредственно следуя рекуррентному соотношению, то будут
происходить перевычисления.
3. Рекурсия в алгоритме построения всех маршрутов.
Рекурсия, организованная по схеме f(n)=F(f(n—I),
f(n—2)), неудачна не только когда / и F — числовые
87
функции. Все приведенные рассуждения дословно
переносятся на случай, когда / — функция натурального
аргумента, принимающая значения в некотором
множестве М, a F — функция двух аргументов из множества
М, принимающая значения снова в множестве М.
Такие функции встречаются в алгоритме U (§ 1)
построения всех маршрутов движения шашки с 1-й клетки
на я-ю. Значение f(n) — это слово в алфавите {о, g, <>},
изображающее условленным образом все маршруты.
Функция F применяется к двум словам такого вида и
определенным образом сливает их в одно слово.
Рекурсия в этом алгоритме может быть исправлена
разработанным приемом — переходом к построению двух
совокупностей маршрутов, ведущих на я-ю и- (я—1)-ю
клетки.
Перед составлением алгоритма с такой рекурсией
составим вспомогательный алгоритм, потребность в
котором ощущалась уже при разработке алгоритма U.
Исходные данные этого алгоритма —■ буква и два слова.
Просматривается первое слово; буквы из него удаляются
и присоединяются в начало второго слова так, что в
итоге порядок этих букв меняется на обратный. При
этом всякий раз, когда в первом слове встречается буква
О, ко второму слову сперва присоединяется заданная
буква (о или g), а потом уже <>. Такой алгоритм можно
составить с рекурсиями:
Т: Дана буква а и слова R, S. Изменить слово S,
присоединив к нему слово R так, как
разъяснено выше в тексте;
Т\: если R — « » mo выход;
Т2: U':= голова (/?);
ТЗ: если U =«<>» то S: = w («<$■», a, S) иначе
S: = »(U, S);
Г4: S: = T{a, xeocm(R), S)
Теперь легко написать основной алгоритм:
U': Дано п^2. Построить V—совокупность всех
маршрутов движения шашки с 1-й клетки на
п-ю и W—совокупность всех маршрутов
движения шашки с 1-й клетки на (п—1)-ю;
U'l: если я = 2 то
начало V: = «о»; №:=«»; выход конец;
U'2: построить V и W для п—i с помошрю
алгоритма V;
U'3: A:=V;
88
f/Ч: V:=T(«o»,V, « »);
U'5: V:=-»(*0», V);
U'Q: если W = « » то V: = w(«g», V) иначе "
l/:-T(«g», UP, K);
• U'7: W:=:A
Задача 4. Сколько проверок равенства п=2 требует
применение алгоритма £/'?
§ 4. Как выполнять рекурсивные алгоритмы
1. Подготовка трассы. В рассмотренных примерах
мы имели дело с рекурсивными алгоритмами, которые
легко преобразовывались в нерекурсивные — как
правило, рекурсия могла быть заменена одним циклом.
Бывают ситуации и посложнее. Пусть h (n) — некоторая
функция натурального аргумента такая, что значение
h (n) — всегда целое число из отрезка [0,9]. Например,
h (n) может быть л-й цифрой после запятой в десятичном
представлении числа я. Теперь определим функцию
f(n) для всех целых неотрицательных п:
[ п, если 0^п^9,
\ h(n)f{n—1—h(ri))-\-n в остальных случаях.
Функция /(«) задана рекуррентным соотношением
десятого порядка; его особенность в том, что для каждого
вычисления f(n) из значений f(n—1), ..., f(n—10)
используется только одно — f(n—1—/г (л)). Значения
f(n—1), ..., f(n—h(n)) заведомо не нужны (и их не
хотелось бы вычислять); из всех начальных значений
тоже потребуется лишь одно.
Чтобы вычислить /(/г) придется определить и
запомнить конечную последовательность чисел п0, nlt ...
..., nk, где п0=п, Я1=я0—п(«о)—1, n2=nir—h(n1)—1, . ..
..., nk=nk-1—h(nh-1)—\, nft_i>9, 0<%<9.
Задача 1. Доказать, что в последовательности чисел п0,
пъ ... действительно найдется некоторое п^ такое, что 0«Л£«:9.
Видно, что п0, пи ..., пк — это те числа, для
которых придется вычислить значение функции /, если мы
хотим узнать f(n). После того, как л0, пи ..., nh
определены, значение / (п) вычисляется в несколько
однотипных этапов:
f(rih)=nh,
/(nfc_1)=A(nk_1)-/(nfc)+l, .... /(/i„)=ft(rt.WM+l-
§9
В процессе построения последовательности пв,
пи ..., nh нам пришлось вычислить h (n0), h (th),...; для
того, чтобы не вычислять эти значения заново,
последовательность /i(rto), h(tii), ..., h(nh) можно запомнить
вместе с п0, пи ..., nh. Таким образом, не исключены
случаи (и они наиболее интересны), когда первоначально
необходимо проложить трассу — т. е. найти некоторую
последовательность значений аргумента функции,
двигаясь от п к начальным условиям, а затем пройти эту
трассу в обратном направлении, вычисляя значения
функции при найденных значениях аргумента.
Возможно, что вместе со значениями аргумента придется
подготовить еще какие-то последовательности, элементы
которых также в обратном порядке $удут использованы
при вычислении искомого значения функции.
Рекурсивные обращения в алгоритме оправданы
именно в тех случаях, когда перед окончательными
вычислениями необходимо прокладывать трассу. Если эта
трасса видна и так, то лучше составить циклический
алгоритм.
На идее подготовки трассы и последующего ее
прохождения в обратном направлении основан общий метод
выполнения рекурсивных алгоритмов. Этот метод будет
продемонстрирован на алгоритме вычисления функции
f(n). Относительно выполняемого алгоритма (обозначим
его А) будут сделаны два предположения:
Г алгоритм А определяет функцию, т. е. по одному
или нескольким объектам-аргументам вырабатывается
один объект;
2° рекурсии алгоритма А состоят в том, что
имеются шаги, представляющие собой приказы вроде
s:=A(p), где р — либо переменная, либо конкретный
объект.
Эти предположения не являются на самом деле
существенными. Но если их принять, изложение
упростится. Составим алгоритм вычисления f(n),
удовлетворяющий этим предположениям (будем считать, что h —
заданная операция или уже определенная функция):
/1: если п<Сд то начало z:—n; выход конец;
/2: v:=h(n);
/3: k:=n—l— v;
/4: l:=f(k);
/5: z:=vl+n
Полученное значение z — искомое.
90
Пусть ri>9. Шаги /1, /2, /3 выполняются как обычно.
Шаг /4 таков, что нужно на время забыть о предыдущих
вычислениях, вычислить f(k), а затем вспомнить все
вычисленные значения (п, v, k) и возобновить работу
с нужного места, т. е. с шага /5.
Для вычисления /(/г) в свою очередь потребуется на
время забыть значения тех же переменных и вычислить
функцию / для меньшего значения аргумента. Так
пойдет вплоть до некоторого простого случая. Итак,
несколько раз потребуется временно забывать ряд
величин. Затем начинается период воспоминаний и
возвращений к тем местам алгоритма, где вычисления
прерывались. То, что было забыто последним, вспоминается
в первую очередь. То, что было забыто предпоследним,—
во вторую и т. д.
2. Магазин. Идея состоит в том, чтобы вести список
порций «забываемых» объектов. Занесение порции в
синеок происходит в момент прерывания вычислений
из-за рекурсивного обращения. В каждую порцию
включаются:
а) переменные и их значения;
б) переменная, которой нужно присвоить значение,
вычисленное при рекурсивном обращении;
в) название шага, начиная с которого нужно
продолжать прерванные вычисления.
Когда вычислительный процесс дойдет до одного из
простых случаев, нужно будет определить значение
функции и приступить к прочтению последней порции.
Прочитав ее, следует:
а) восстановить значения переменных,
б) присвоить указанной переменной значение
функции,
в) перейти к нужному шагу.
Прочитанная порция больше не нужна — она
удаляется из поля зрения. После вычисления нового
значения функции восстановление нужно будет
производить в соответствии со следующей порцией и т. д.
Вычислим значение /(25). Для получения значений h(n)
воспользуемся тем, что
я=3,14159 26535 89793 23846 26433 ...
Шаги /1, /2, /3 выполняем как обычно. Далее записываем
порцию:
„=25, v=3, /г=21, /, /5
и переходим к вычислению /(21).
91
Список порций удлиняется:
п=25, о=3, fc=21, /, /5;
п=21, о=2, 6=18, /, /5.
Переходим к вычислению f (18). Вновь удлиняем список:
л=25, о=3, /г=21, J, /5;
«=21, о=2, й=18, /, /5;
п=18, о=8, /г=9, /, /5.
Переходим к вычислению /(9). Шаг /1 дает ответ 9.
Прочитываем последнюю порцию. Согласно этой порции
нужно присвоить n: = 18, o:=8, k:=9, /:=9 и
приступить к выполнению шага f5. Перед выполнением /5
укорачиваем список на одну (последнюю) порцию:
ft=25, о=3, £=21, /, /5;
п=21, о=2, ft=18, /, /5.
В результате выполнения шага /5 переменная z
получит значение о/+/г=8х9+18=90. Выполнение данного
этапа алгоритма заканчивается. Прочитываем
последнюю (из оставшихся) порцию. Выполняем присваивания
n:=21; o:=2; й: = 18; /:=90, удаляем прочитанную
порцию и переходим к шагу /5. Переменная г получает
значение 2x90+21=201. К этому моменту список
имеет вид п=25, о=3, £=21, I, /5. Поступаем с
последней порцией так, как поступали раньше. Получаем
искомое значение функции: 3x201+25=628.
Задача 2. Вычислить /(24).
В подобных случаях часто говорят, что порции
записываются в магазин. Магазин — это хранилище
данных ' с таким строением, что последнее из попавшего
туда извлекается оттуда первым, предпоследнее —
вторым, ..., первое—последним.' В названии
подразумевается сходство с магазином огнестрельного оружия.
Придерживаясь этой терминологии, мы в дальнейшем
будем говорить не о списке, а о магазине.
3. Обобщения. Достоинство разобранного метода
заключено, в частности, в том, что он позволяет
выполнять рекурсивные алгоритмы, содержащие более одного
рекурсивного обращения. Возможны ситуации, когда
алгоритм не содержит явных рекурсивных обращений,
но содержит обращение к другому алгоритму, который
в свою очередь обращается к первому. Явные и неявные
рекурсивные обращения могут присутствовать
одновременно. Во всех случаях для выполнения рекурсивного
алгоритма предложенный метод обеспечивает решение
92
задачи, потому что в магазине, если он не пуст, мы всегда
находим наименование следующего шага (в
частности, назва'ние алгоритма) к выполнению которого
нужно приступить, если же магазин пуст, то
закончилось вычисление самого первого обращения к алгоритму,
следовательно, все вычисления закончились.
Когда мы сталкиваемся с рекурсивными алгоритмами
в геометрии, мы попадаем в более сложное положение,
чем с функцией f(n). Непонятно, что значит записать
переменную вместе с ее значением (точкой) в магазин.
Один из выходов состоит в том, • что изготавливаются
копии плоскости построения. На каждой копии вместе
I / W \\
А, В, С, F5jA,B С, F5\ A,B,C,F5
Рис. 29.
с точками отмечены их обозначения. Копия упрятывается
в магазин, а на основной плоскости убираются
некоторые из старых точек и добавляются новые, которые
получают ранее использовавшиеся обозначения. Затем
копии поочередно извлекаются из магазина, по ним в
плоскости построения восстанавливаются забытые точки.
При проведении построений на листе бумаги в
магазин, который размещается на этом же листе, можно
заносить названия точек, а от этих названий проводить
стрелки к построенным точкам. В таких случаях
говорят, что магазин содержит не сами объекты, а ссылки
на них. Пример такого магазина приведен на рис. 29.
Переменная С здесь должна получить в качестве
значения точку, являющуюся результатом рекурсивного
обращения; F5 — обозначение шага алгоритма.
Хранение ссылок в магазине удобно и тогда; когда
объекты, с которыми приходится иметь дело, слишком
громоздки. В этом случае переписывание объекта
требует значительной затраты сил. Поэтому заносить в
магазин имеет смысл сведения о том, где уже выписан
Данный объект.
93
* * *
Выяснено, что выполнение рекурсивного алгоритма—
дело непростое, но сложности выполнения здесь скрыты
от глаза. При анализе рекурсивного алгоритма мы
будем стараться учитывать, что, помимо действий над
объектами, он предполагает действия с магазином —
действия занесения и выемки. Кроме того, под
магазин выполняющим алгоритм должно быть отведено
место. Полезно помнить, что при вычислении п\ по
рекурсивному алгоритму, первоначально будут
записаны в магазине все числа п, п—1, п—2, ..., 1, а затем
уже будет вычисляться их произведение.
Циклическое вычисление не требует манипуляций с
магазином. Поэтому для выполняющего алгоритм
желательно, чтобы рекурсии были по возможности заменены
циклами. Такую замену выполнить несложно в тех
случаях, когда ясно видна трасса от одного из
простейших случаев к нужному. Именно так обстоит дело с
вычислением п\ — начинаем с 1 и вычисляем
последовательно 1x2, 1x2x3, ... От рекурсии труднее
избавиться, когда предварительно нужно проложить трассу,
а потом уже пройти ее в обратном направлении — как
получилось с функцией /. Здесь применение рекурсии
оправдано. Напоследок
приведем пример алгоритма
геометрического построения,
который существенно исполь-
Рис. 30. Рис. 31.
зует рекурсию. Алгоритм опишем неформально.
(Этот пример взят из книги Л. И. Головиной и И. М. Яг-
лома «Индукция в геометрии», «Физматгиз», 1961 •)
На плоскости дано 2п+1 точек. Построить (2п-И)'
угольник, для которого эти точки являются серединами
94
сторон. Если м=1, то нужно построить треугольник по
серединам Аи А2, Аа его сторон: проводим через
каждую из данных точек прямую, параллельную прямой,
соединяющей две другие точки (рис. 30). Иначе
переходим от п к п—1 (т. е. уменьшаем число вершин на 2)
следующим образом: строим параллелограмм по трем
вершинам Ain-lt Аы, А2п+1. Четвертая вершина
параллелограмма и данные точки Ai, A2, ..., А2п-г
рассматриваются как новые (более простые) исходные данные
задачи. После того как для этих данных задача решена
и построен (2п—1)-угольник, то он легко может быть
переделан в искомый (2и+1)-угольник (рис. 31).
Задача 3. Восполнить пробелы в последнем рассуждении.
§ 5. Пример избавления от рекурсий
Рекурсия во многих случаях позволяет придать
алгоритму ясную и естественную структуру. Это,
несомненно, является достоинством рекурсии как средства
Рис. 32.
описания алгоритмов. Но, с другой стороны,
присутствие рекурсивных обращений доставляет
дополнительные неудобства выполняющему алгоритм, поэтому часто
рекурсивный алгоритм служит подготовительным
вариантом, а окончательным является более подробный
алгоритм. Ниже дается пример переработки
рекурсивного алгоритма в нерекурсивный и обсуждаются
последствия этой переработки.
1. Игра «ханойская башня». Доска имеет три
колышка. На первом нанизаны п дисков убывающего вверх
диаметра (рис. 32). Требуется, перекладывая диски по
одному, расположить их в прежнем порядке на третьем
колышке. Ограничение состоит в том, что больший
Диск не может никогда располагаться над меньшим.
95
Нашей задачей будет разработка алгоритма
построения перечня всех необходимых перекладываний (ходов).
Если колышки обозначить какими-нибудь буквами,
например а, Ь, с, то перечень может быть представлен
словом в алфавите {а, Ь, с). Так, слово abacbc означает,
что снимается верхний диск с а и перекладывается на Ъ,
затем опять снимается верхний диск сан
перекладывается на с, затем снимается верхний диск с b и
перекладывается на с. Буквы с нечетными порядковыми
номерами суть имена колышков, с которых снимаются
диски. Буквы с четными порядковыми номерами —
имена колышков, на которые перекладываются диски.
Рис. 33.
К решению приводит следующее соображение. Чтобы
получить возможность переложить нижний (самый
большой) диск с первого колышка на третий, необходимо,
чтобы все диски, кроме самого большого, были нанизаны
на второй колышек (рис. 33). После того как самый
большой диск будет перенесен с первого колышка на
третий, останется перенести п—1 диск со второго
колышка на третий. Так как для самого простого случая
я=1 решение задачи ясно (одно перекладывание), то
можно считать, что получена схема алгоритма решения
задачи для любого натурального п. Алгоритм будет
содержать два рекурсивных обращения. Оба обращения
сводят задачу к количеству дисков, равному п—1.
Задача 1. Доказать, что предложенный способ позволяет
решить задачу за наименьшее из возможных число перекладываний.
Описывая алгоритм, будем пользоваться обычными
операциями над словами: голова, хвост, w, = , операцией
уменьшения числа на 1 (назовем ее sub (k)) и логической
операцией сравнения числа k с единицей (назовем ее
one{k)).
96
L: Даны буквы х и у (хфу) из алфавита {а, Ь, с)
и натуральное п. Нужно построить слово I
в алфавите {а, Ь, с}, изображающее перечень
перекладываний п дисков с колышка с именем х
на колышек с именем у по правилам игры
«ханойская башня»;
L\: если опе(п) то начало 1:=^^(х, у); выход конец;
L2: если ~| (л; = «с» V У — «с») то г: = с
иначе если х = «&» V У = «Ь» то г\— «а»
иначе г: =«Ь»;
L3: т: —sub(n);
L\: I: — L(x, z, m);
£5: k: —L(z, y, m);
L6: l: = "(l,x,y,k)
Шаг L2 определяет имя третьего колышка, которое
не указано в числе аргументов. Рекурсивные обращения
содержатся в шагах L4, L5. Подсчитаем, сколько
перекладываний дисков придется проделать при решении
задачи для данного п. Пусть это число есть ап *).
Величина ап складывается из перекладываний п—1 диска
с колышка х на колышек z (шаг L4), одного
перекладывания с колышка х на колышек у и перекладываний
п—1 диска с колышка z на колышек у (шаг L5).
Получаем an=an_i+l+a„_1, т. е. u„=2fln_i-f-l. Ясно, что
ai=l. Общее решение однородного соотношения ап~
—2ап-! есть с2п, —1 удовлетворяет соотношению ап—
=2an_i+l; следовательно, нужно подобрать с так,
чтобы ей1—1 = 1. Получаем с=1 и а„=2"—1.
В алгоритм L включен шаг L3: m:=sub{n), потому
что число т=п—1 используется в шаге L4 дважды.
Исследуем, как меняется число вычитаний 1 за счет
введения переменной т. Если все сделано, как в
алгоритме L, то число обращений к операции sub при данном
п, обозначенное через tn, может быть описано
рекуррентным соотношением
^=2^+1 (1)
с начальным условием ^=0.
Если выбросить приказ m:=sub(n) и в шагах L4, L5
вместо т подставить sub(h), то для числа t'n обращений
*) С этого момента для упрощения записей рекуррентных
соотношений, вместо а(п), Ь{п), . . . будем писать ап, Ьп, . . . .
4 с. А. Абрамов 97
к операции sub получим соотношение
Гп = 2Гп_1 + 2 (2)
при начальном условии t[ = 0.
Вычитая почленно из соотношения (2)
соотношение (3), получаем
f;-*n=2(^-/„.о+ 1, t[-t=o.
Вводя обозначение sn~t'n —1„, получаем
рекуррентное соотношение
Его решение s„ = 2"_1—1.
Задача 2. Чему равно t„7 Почему это число не равно п—1?
Ответ на второй вопрос. L(x, г, т) и L(z, у, т) требуют
независимого вычисления sub(m).
Таким образом, из-за ничтожной экономии на одном
шаге в целом получаем выигрыш, растущий, как
показательная функция от п. Подобные явления уже
наблюдались, для рекурсии они характерны. Однако
выигрыш этот не обходится даром, за него приходится
расплачиваться памятью. Если алгоритм будет
выполняться с помощью магазина, то при каждом рекурсивном
обращении переменная т должна будет упрятываться
в магазин, а позднее извлекаться из него. Каждая
упрятываемая в магазин порция содержит элемент т —...,
где под многоточием подразумевается некоторое числовое
значение. Подсчитаем, на сколько элементов увеличится
объем памяти, занятой под магазин, при переходе от
алгоритма без переменной т к алгоритму L. Пусть эта
величина равна vn. Шаг L5 выполняется после того,
как закончено выполнение L4. Следовательно, к моменту
выполнения Lb в магазине не останется никаких следов
выполнения L4. Поэтому vn=vn-i~\-l и i»i=0. Отсюда
получается, что vn=n—1. Объем расходуемой памяти
растет линейно.
Получили, что при п=10 можно выбирать из двух
затрат: либо 29—1 = 511 избыточных вычислений, либо
хранение в магазине девяти чисел.
2. Переход к одному рекурсивному обращению.
В алгоритме L два рекурсивных обращения. Общее
число гп обращений к магазину при упрятывании
порций данных при решении задачи для п дисков
определяется соотношением /-n=2rn_1+2, ri=0. Отсюда не-
98
трудно получить, что /-„=2"—2, т. е. гп растет как
показательная функция. Это число можно уменьшить,
если заметить, что слово L(z, у, т) отличается от слова
L (х, г, т) только заменой z на х, у на z и соответственно
х на у. Коль скоро построено первое слово, нетрудно
создать второе. Для избавления от второго рекурсивного
обращения следует шаг L5 заменить
последовательностью шагов:
L5.1: и: = 1;
L5.2: ft:=« »;
L5.3: повторять начало w: = голова (и);
если w — x то w:=y иначе
если w = z то w: = x иначе
w: — г;
k: = "(k, w);
и: = хвост (и)
конец
пока не и = « »
Нетрудно видеть, что обращение к магазину будет
происходить при переходах п->п—1->п—2->-.. .-*-1—
их будет п—1 (вместо 2™—2 при двух рекурсивных
обращениях). Обращений к sub будет тоже п—1: при
каждом обращении к L (кроме последнего) — одно
вычисление sub (n).
' Задача 3. Выписать и решить рекуррентные соотношения
для числа обращений к магазину и к sub. Убедиться, что в обоих
случаях получается решение п—1.
3. Нерекурсивный алгоритм. При п > 1 имеет место
L{x, у, n) = ^{L(x, z, п— 1), х, у, L(z, у, п—\));
в этом равенстве z означает букву алфавита {а, Ь, с],
отличную от букв — значений переменных х и у.
Слово L(z, у, п—1) несложно получить из слова
L (x, z,n—1). Но слово L(x, z, n—1) устроено сходно
с L (х, у, п) — оно тоже состоит из трех частей.
Вторая часть — это две буквы, изображающие один ход,
а третья получается из первой некоторой заменой
букв. Нужно знать самый первый ход, правила
замены и «промежуточные» ходы, тогда можно будет
обойтись вообще без рекурсий. Правило замены будем
изображать таблицей из двух строк. Например,
•х у z\ означает, что х заменяется на г, у—на х и
\г х у J
г —на у. Первоначально задача сводится к построению
4*
99
L(x,z,n—1), промежуточный ход изображается
словом ^ (х, у) и правило замены для получения
третьей части слова из первой есть (х v г\ . Этот
этап упрощения задачи и несколько следующих можно
записать схематично:
х у г
1° L(x, г, п—1), "(х, у), Хгху
2° Цх,у,п-2), -(х, г), (***
3° L(x,z,n-3), »(x,y), [хгЦ
4° Цх,у,п-4), "(*,z), (***),
Видно, что таблицы чередуются и таблице (хуг
\2 X у
соответствует промежуточный ход ^(х,у), а таблице
х У г\—ь-(х, г). Следовательно, самый первый ход
определяется четностью п. Пусть п четно, тогда
последние этапы по аналогии с предыдущим
записываем в виде:
n-l° L(x,z, 1), »(х,у), (ху/у
п° L(x, z, 1).
В таком случае первый ход—это L(x, z, 1) = °(#, г).
Пусть п—нечетно, тогда последние этапы
записываем так:
п-1° L(x, у, 1), «(*, г), [xyYx
п° L(x, у, 1),
и первый ход—это L (х, у, l) = w(x, у).
Присвоим таблице (х уг\ номер 1, а таблице
х у 2 )— номер 2. Точно так же w (x, г) — ход но-
z к у j
мер 1, ^ (х, у) — ход номер 2. Проясняется метод
решения задачи без рекурсий для любого п. Задача
решается в п этапов. Этап с номером I дает
построение слова L(x, г, i) или L(x, у, i), а именно того
слова, которое упомянуто в пункте п — Г. На i-u
этапе вычисляется номер таблицы t, которая
потребуется для замены на t'-rl-м этапе.
100
Вот набросок алгоритма:
V: условие то же что и для алгоритма L;
L'l: если четное (п) то
начало I: = «(х, z); t: = 2 конец
иначе
начало I: = " (х, у); t: — 1 конец;
L'2: повторять начало
и: = I;
приписать к I ход (две буквы) с
номером t, затем к полученному
приписать слово, получающееся из и
заменой букв по таблице с
номером t;
п: = sub (n);
если t = l то t: = 2 иначе t: = l
конец
пока не one (n)
Шаг L'l содержит обращение к логической операции
четное (п). Если не предполагать, что эта операция
входит в набор допустимых операций, то ее можно
описать в виде алгоритма с операциями sub и one.
Задача 4. Выполнить это описание.
Шаг L'2 нуждается в детализации. Тут удобно иметь
функцию замена (s, /), где s — это слово в алфавите
{а, Ь, с}, j — номер таблицы, равный 1 или 2. Функция
принимает значение, равное слову, которое получается
из s заменой по таблице /. Чтобы вычислить значение
функции замена, необходимо знать значения переменных
' х, у, z, иначе нельзя будет воспользоваться таблицей.
Переменные х, у, z будут глобальными по отношению
к алгоритму замена.
Представляется удобным и алгоритм ход (/),
значением которого является слово w (х, г) или " (х, у)
в зависимости от того, равно / единице или двум.
Вот алгоритмы L' и замена (в алгоритме V
становится ненужной переменная и):
V: условие прежнее;
L'l: если четное(п) то
начало 1: = ^ (х, z); t: — 2 конец
иначе начало t: = w {x, у); t: = 1 конец;
L'2: повторять начало
I: = w (I, ход (t), замена (I, ());
n:—sub(n);
101
если t = \ то t:—2 иначе t: = \
конец
пока не one (n)
замена: Дано слово s и номер таблицы /.
Получить слово v, заменив буквы слова s
по таблице с номером j. Переменные х, у, г —
глобальные;
замена 1: v. = « »;
замена 2: повторять начало
d: = голова (s);
если t = 1 то
начало
если d = x то е: — у иначе
если d = y то e:^z
иначе е:—х
конец;
если t = 2 то
начало
если d = x то е: — г иначе
если d = y то е: = х
иначе е:—у
конец;
v. = w (v, d);' s = хвост (s)
конец
пока не s = « »
Задача 5. Описать алгоритм ход.
Описанный процесс построения нужного перечня
(слова) внешне схож с процессом роста кристалла:
там тоже происходит разрастание с некоторым
подобием симметрии.
Задача 6. Выбрав другую форму представления
последовательности ходов и таблиц замены можно существенно сократить
описание алгоритма перекладывания п дисков с первого колышка
на третий. Будем изображать последовательность ходов в виде
числового массива vlt ti2, ... Каждое число — это номер колышка
/1 2 3\ /1 2 3\
(1, 2 или 3). Две таблицы замены ( о q i ) и ( о . 9 ) запишем одной
таблицей fg i 9 ) — из старых таблиц взяты только нижние строки.
Условимся обозначать элемент новой таблицы через а,-у, где (' —
номер строки, / — номер столбца (1<(<2, 1</<3). Таким образом,
у нас появляются переменные с двумя индексами и двумерные
массивы. Замена элемента vk по таблице с номером t задается
выражением й\у..
102
Убедиться в правильности последнего утверждения и составить
алгоритм, использующий описанную форму представления
последовательности ходов и таблиц. В алгоритме допускаются обращения
к простейшим арифметическим операциям.
Задача 7. Пусть диски в игре «ханойская башня» окрашены
в черный и белый цвет: самый маленький — черный, второй —
белый, третий — черный и т. д. Подставка под первым колышком
окрашивается в черный цвет, если самый большой диск — белый
и окрашивается в белый цвет, если самый большой диск — черный.
Подставка под третьим колышком окрашивается в тот же цвет,
что и подставка под первым, а подставка под вторым — в
противоположный цвет.
Доказать, что необходимые перекладывания можно совершить,
руководствуясь следующими правилами:
1° никогда не класть больший диск на меньший, •
2° никогда не класть черное на черное и белое на белое,
3° вслед за некоторым перекладыванием никогда не совершать
обратного перекладывания.
Глава IV. ПОИСК
Задача выбора из конечного числа возможностей
почти всегда допускает в качестве решения поочередное
рассмотрение последствий выбора каждой из
возможностей. Часто полный перебор оказывается излишним —
непригодность некоторых возможностей позволяет не
рассматривать еще какие-то возможности. В этой главе
разбираются методы организации и сокращения поиска.
С этого момента мы будем иметь дело лишь с одним
видом объектов — числами. Без специальных оговорок
будет считаться, что набор допустимых операций
включает в себя элементарные- арифметические операции.
Это ограничение, с одной стороны, избавит нас от
необходимости каждый раз указывать характер объектов
и перечислять допустимые операции. С другой стороны,
это ограничение во многих случаях несущественно.
Идея алгоритма переносится на родственную задачу
с другими видами объектов.
§ 1. Справочник и поиск сведений в нем
Иногда требуется многократное повторение
процедуры переработки одного объекта в другой с помощью
некоторого перечня пар объектов (аи »i), (a2, о2), •••
(ап, Ьп). Так обстоит дело при переводе иностранного
текста со словарем, кодировании набора символов при
помощи таблицы кодов и т. д. Задается объект х,
которому нужно найти равный среди аъ аг, ..., ап. Пусть
х=аг-, тогда bt представляет собой искомое значение.
Можно сказать, что два массива аи а2, ..., ап и Ьи Ь2, ...
..., Ьп образуют справочник. Изучим вопрос
трудоемкости поиска в справочнике при различных
расположениях элементов в нем. Иногда можно изменить нуме-
104
рацию в массиве аи а2, .... ап и соответственно в Ьи
Ьг, ..., Ьп так, что поиск станет более легким.
Единственная трудность поиска в справочнике — поиск числа
i такого, что x=at. Следовательно, можно
рассматривать задачу именно в этом аспекте, не занимаясь
массивом bi, b2, ..., bn.
1. Поиск элемента с данным значением в массиве.
Если в наборе допустимых операций есть только
отношение равенства между числами, то ничего лучшего не
остается, как последовательно сравнивать х с аь ...
..., ап и, как только обнаружится равенство, указать
значение индекса. Коль скоро у всех аь аа, ..., ап
шансы совпасть с х равны, для поиска индекса
потребуется в среднем п/2 сравнений.
Поиск может быть сокращен, если допустить
проверки отношений неравенства. Рассмотрим задачу. Играют
двое. Первый играющий задумывает произвольное целое
число от 1 до 1000. Второму разрешается задавать
вопросы типа «верно ли, что задуманное число больше
такого-то?» Первый отвечает «да» или «нет». Требуется
доказать, что для угадывания достаточно десяти умело
поставленных вопросов.
Все дело в том, что второй участник любым своим
вопросом разбивает множество подозреваемых чисел на
два непересекающихся подмножества. После ответа «да»
или «нет» становится известным, в каком из двух
подмножеств нужно продолжать поиск. Если, например,
в качестве первого вопроса предложить «верно ли, что
задуманное число больше 1?», то есть вероятность уга-
дазъ число за один вопрос. Но если ответ будет «да»,
то заданный вопрос мало что даст для дальнейшего —
придется вести поиск среди 999 чисел. Самое лучшее —
это разбивать множество каждым вопросом на два
подмножества с равным количеством элементов, а если число
элементов множества нечетно, то разбивать так, чтобы
эти количества отличались на 1. Вопрос «верно ли, что
задуманное число больше 500?» хорош тем, что
независимо от ответа переходим к поиску в множестве из
500 элементов. Если был получен ответ «да», то вторым
вопросом будет «верно ли, что задуманное число больше
750?», иначе ■— «верно ли, что задуманное число больше
250?» и т. д. На рис. 34 дана таблица, в верхней строке
которой приводится номер вопроса, а под номером • -
то количество чисел, для которого при наиболее не-
105
благоприятном исходе второму играющему придется
продолжать поиск после получения ответа на вопрос.
Задача 1. Указать наименьшее N такое, что для угадывания
задуманного числа из диапазона от 1 до N может оказаться
недостаточным 10 вопросов.
Вернемся к поиску в массиве аи ..., ап числа со
значением х. Если задавать только вопросы типа «верно ли,
что х равно а с таким-то индексом?», то каждым таким
вопросом мы разбиваем весь массив на две части: первая
;
500
2
250
3
125
4
63
5
32
6
16
7
8
в
4
9
2
10
/.
Рис. 34.
часть содержит один элемент, а вторая — (п—1).
Хотелось бы и тут иметь возможность задавать вопросы,
определяющие разбиение массива на две примерно
равные части. Для этого надо, чтобы массив ах, ..., ап
был упорядоченным (а^а^.. -<.ап). Тогда, взяв k=
—Ы12] и получив ответ на вопрос «верно ли, что х~>ак?»,
можно, в зависимости от ответа, переходить к поиску
среди щ, ..., ak или среди ah+i, ..., ап. Получается,
что если массив упорядочен, то поиск можно проводить
быстро. Алгоритм поиска будет выглядеть так:
А: Дан массив аг<1а2<С . .<.ап и число х.
Построить k такое, что ah=x (предполагается,
что такое k существует);
А\: k: = \;
А2: 1:=п;
A3: пока k ФI выполнять
Гй-4-Г
начало т: = —— ;
если х > ат то k: = m -f 1
иначе 1: = т
конец
Этот алгоритм называют алгоритмом деления пополам.
Оценку для числа сравнений элементов массива с х
в этом алгоритме устанавливает следующая
106
Теорема ,1. Алгоритм деления пополам в
применении к массиву а1<аа<.. .<.ап и числу х требует не
более [log2n]+l сравнений.
Доказательство. Покажем, что если для
натурального s выполнено 2s-1<.n^2s, то число
сравнений ^s. Из этого будет следовать утверждение
теоремы.
Проведем индукцию по s.
Г Пусть s=l', тогда п—2. Требуется одно сравнение.
2° Пусть утверждение верно для всех s, не
превосходящих натуральное k. Докажем справедливость
утверждения для s=k+l. Если п четно, то после одного
сравнения переходим к поиску среди и/2 элементов.
Очевидно, что 2k~1<Ln/2?^2k. По предположению
индукции, потребуется теперь не более k сравнений.
Общее число сравнений не превосходит, таким образом,
k-r\. Пусть /г — нечетное. В этом случае 2*<n+1^2fe+l
(пф2к+1). Выполнив одно сравнение, переходим к
поиску среди элементов, количество которых ^(/г+1)/2.
В силу неравенств 2ft_1<(n+l)/2^2ft верно
утверждение теоремы.
Задача 2. Какова граница для числа сравнений при поиске,
в массиве из 1000, 2000, 3000 элементов?
Задача 3. Показать, что в теореме вместо [log2«]+l можно
взять наименьшее целое число, большее или равное log2«. (Такая
оценка более точна для случая n=2s.) Показать, что это число
равно — [—log2n].
Теорема 2. Не существует алгоритма, который
требовал бы сравнений меньше, чем алгоритм деления
пополам.
Доказательство. Пусть мы обладаем
некоторым алгоритмом, который требует не более т
сравнений. Результаты т сравнений можно записать в виде
m-элементной последовательности слов «да» и «нет».
Наш алгоритм фактически позволяет по такой
последовательности выбрать нужный элемент. Всего элементов п
штук, и каждый из них может оказаться тем, который
разыскивается. Это означает, что для любого i
существует последовательность из т слов «да» и «нет»,
указывающая на то, что at — искомый. Поэтому должно
существовать п последовательностей слов «да» и «нет»,
каждая из которых содержит не более т слов. Из этих
последовательностей никакая не должна быть началом
некоторой другой, более длинной последовательности.
107
Таким образом, число этих последовательностей не
больше, чем число всех последовательностей из т слов,
т. е. 2т. Получаем, что 2т^нг и m^log2n.
2. Упорядочивание массива (сортировка). Рассмотрим
теперь задачу упорядочивания элементов аи ..., ап
по возрастанию. Существует п\ взаимных расположений
элементов аь ..., ап. Для каждого из этих
расположений требуется своя последовательность перемещений
элементов, приводящая к упорядоченности по
возрастанию. Рассуждая, как прежде, получаем, что если мы
обладаем алгоритмом упорядочивания, требующим не
более т сравнений элементов, то 2т~^п\ и m^log2(n!).
Ниже будут построены алгоритмы с числом сравнений,
близким к log2 (я!).
Задача упорядочивания может быть решена в п
этапов. На каждом i-u этапе находится решение задачи
применительно к подмассиву аг, а2, ..... at. На первом
этапе надо построить упорядоченный массив из одного
элемента. Но массив из одного элемента всегда
упорядочен. Когда мы переходим к i'-му этапу при £>1, то,
поскольку перед этим выполнен (i—1)-й этап, задача
заключается в том, чтобы добавить один элемент к уже
упорядоченному массиву. Набросок алгоритма:
В: Дан массив аи а2, ап. Переставить
элементы массива так, чтобы после перестановки
они были упорядочены;
В\: i:=2;
В2: пока i^.n выполнять начало
включить элемент at в
упорядоченный массив
fli, ..., #i-i",
конец
Для at нужно найти новое место между элементами
массива ах, а2, ..., аг_х; предположим, что это место
находится между a,-_i и а,). Это значит, что а}, a]+i, ...
at-i нужно сдвинуть на одно место вправо: at-i на место
ait at-2 на место аг_!, ..., а} на место aj+1, после чего
at вставить на освободившееся место. Число / можно
найти, просматривая at-h, k=\, 2, ..., и проверяя для
каждого из них, не выполнено ли a,>a;_ft. Как только
для некоторого k условие окажется выполненным,
можно будет положить j=i—k+\. Если условие не
будет выполнено ни разу, то at встанет на первое место
108
(/=1). Поступая таким образом, придется при поиске
места для at проделать k сравнений, lsglfejgj—1. Для
упорядочивания всего массива придется проделать число
сравнений, находящееся в пределах от п—1 до
л
2(i—l)=n (n—1)/2. В среднем потребуется (ft+2) (n—1)/4
сравнений.
В предыдущем пункте говорилось, что поиск
элемента в упорядоченном массиве можно производить
довольно быстро, если воспользоваться алгоритмом
деления пополам. С незначительными изменениями этот
алгоритм можно приспособить и для нахождения места
элемента. Пусть в рассматриваемом массиве нет
элемента со значением х, но мы тем не менее применяем
алгоритм А и получаем некоторое k. Нетрудно видеть,
что если х не превосходит наибольшего элемента
массива, то k — значение индекса, которым должен обладать
х после вставки в массив, в противоположном случае
значение индекса равно k+l. Таким образом, для
нахождения места элемента можно применять алгоритм С,
первые три шага которого совпадают с тремя шагами
алгоритма А, а четвертый шаг —
С4: если x~>ah то k:—k-{-\.
При сдвиге группы элементов a,, ai+i, ..., a,_j
нужно иметь в виду, что, прежде чем аг_1 будет
поставлен на место at, надо сохранить значение ait присвоив
его вспомогательной переменной г. Иначе мы потеряем
его и не будем знать, какое значение нужно будет
присвоить переменной а}. По той же причине надо сдвигать
элементы jUj, aj+u ..., at-u начиная с аг_1 и кончая а},
чтобы занимать место в массиве после того, как оно
освободилось. Все это учитывает алгоритм В:
51: i:=2;
В2: пока i^ln выполнять
начало
с помощью С найти место (индекс /)
элемента at в упорядоченном массиве
Ci, ...., ui-i,
r:=at; t: = i;
пока t>j выполнять
начало at:=at-u t: = t—1 конец;
ау.=г; i: — i+l
конец
109
Если считать, что на поиск места элемента в массиве
из i элементов уходит примерно {log2t]+l сравнений,
то на упорядочивание по алгоритму В массива аи ...
..., ап уйдет log2H-log22-T-...+loga(n— 1)+гс— 1 =
=log2(n—1)!+п—1 сравнений.
Задача 4. Числа от 1 до 101 выписаны в произвольном
порядке. Доказать, что из них можно выбрать 11 так, чтобы они
следовали друг за другом в порядке возрастания или убывания.
3. Сокращение числа перемещений элементов при
упорядочивании. Разработанный алгоритм
упорядочивания предписывает довольно большое число
перемещений элементов. При решении задачи включения
элемента аь в упорядоченный массив аи а2, ..., Щ-г быстро
(?slog2i+l сравнений) обнаруживается место, которое
должен занять элемент щ — скажем, он должен
разместиться между а,]-х и aj,— но после этого нужно
переместить a,-, aj+i, ..., at-i на одно место вправо и потом
переместить at на его новое место. Это все требует
выполнить i—;+1 приказ присваивания. Худший случай,
когда аг должен встать на 1-е место — потребуется
выполнить 1+1 приказ присваивания. Лучший — когда
а; остается на своем месте и перемещений (присваиваний)
не требуется. В целом применение алгоритма В требует
п
от 0 до 2(i+l)= (и+4)(п+1)/2 перемещений эле-
1=0
ментов.
Многократно предпринимались попытки придумать
алгоритм упорядочивания, который требовал бы
близкое к log2n! количество сравнений и одновременно
близкое к этому количество перемещений элементов.
Такой алгоритм был придуман фон Нейманом. Его
идея близка идее деления пополам.
Алгоритм не сложно представить рекурсивно:
Г если я=1, то ничего делать не надо;
2° если «>1, то разбиваем массив на два — начало
и конец, причем количества элементов в них либо равны,
либо разнятся на 1. Каждый массив упорядочиваем
описываемым алгоритмом (количество элементов
уменьшилось, грубо говоря, вдвое — задача упростилась)
и сливаем два упорядоченных массива в один.
Здесь основное действие — слияние двух
упорядоченных массивов, скажем di<Ld2<... .<.dh и ey<C.. .<<?,.
Массив /i</2<- • -<.fh+^ который получается в ре-
110
зультате слияния, можно построить в k-\-l однотипных
этапов, так как для определения значения ft потребуется
не более одного сравнения элементов.
Задача 5. Описать алгоритм D построения массива /х<. ..
• • •</„•
Указание. После i-ro этапа элементы flt f2, . . ., f; уже
имеют нужные значения. Ввести величины р и q (p-\-q=i), которые
показывают, сколько элементов из числа dv d2, . . ., dfc и elt . . ., ег
использовано.
Разбиение массивов на более короткие идет до тех
пор, пока не возникнут массивы, каждый из которых
содержит ровно один элемент. Эти «элементарные»
массивы упорядочены. Слиянием соседних массивов
получаем упорядоченные массивы, каждый из которых
содержит два элемента (кроме, быть может, последнего,
которому не найдется парного). Далее массивы
укрупняются той же процедурой. После каждого этапа
укрупнения все получившиеся массивы от первого до
предпоследнего содержат равное число элементов.
Последний массив может оказаться более коротким. Если в
массиве аъ ..., ап выбраны два упорядоченных куска
аи ai+i, ..., aj и а]+и cij+t, ■ ■ ■, cih, то слить их можно
по алгоритму D. Но при таком образе действия
упорядоченные элементы обоих кусков накапливаются в
другом массиве. Попытка устроить все так, чтобы эти
элементы заняли места at, ai+1, .'.., ak, приведет к тому,
что потребуются многократные сдвиги групп элементов.
Достоинство же алгоритма фон Неймана в том и
состоит, что число перемещений элементов сравнительно
невелико, правда, приходится рассматривать'еще один
массив Ьи ■ ■., Ьп. Сливая упорядоченные куски а,-,
ai+i, ..., aj и aJ+1, ..., ah, мы присваиваем значения
элементам bt, bi+i, ..., bh; сливая упорядоченные куски
bh bi+i, ..., bk и bk+1, bh+!!, ..., bm, мы присваиваем
значения элементам ah ai+u ..., ат.
Итак первоначально имеем массив аг, ..., ап,
элементы которого рассматриваются как упорядоченные
одноэлементные куски. Затем в массиве blt .... bn
образуются упорядоченные куски длины 2, .юлучающиеся
слиянием aL и а2, ая и а4, аъ и ае, ... Последний кусок
будет иметь один или два элемента в зависимости от
четности п. Полученные куски сливаются в куски длины 4
(кроме последнего, который тоже всегда упорядочен,
но возможно имеет длину 1, 2 или 3), они последова-.
Ш
тельно записаны в массиве аи ..., ап. Процесс
укрупнения кусков продолжается дальше. Число
упорядоченных кусков убывает — следовательно, настанет такой
момент, когда в массиве аи ..., ап или Ьи ..., Ьп
содержится только один упорядоченный кусок. А это
означает, что массив упорядочен. Рис. 35 демонстрирует
два последовательных этапа укрупнения. Массивы
alt ..., ап и Ь1у ..., Ьп представлены в виде отрезков,
которые разбиты на части, изображающие упорядоченные
куски.
Теперь изучим вопрос о числе сравнений и числе
перемещений элементов. Видно, что каждый этап
укрупнения упорядоченных кусков, сопровождаемый
переходом от а±, ..., ап к Ьи • •., Ьп или наоборот, требует
Рис. 35.
ровно п перемещений и не более п сравнений элементов.
После первого этапа укрупнения кусок приобретает
длину 2, затем 4 и т. д., после s-ro этапа — длину 2*.
Следовательно, число этапов укрупнения есть
натуральное s такое, что 2s~1<n^2s, т. е. s—l<log2n^s.
Отсюда видно, что s<;[log2ft]+l. Число сравнений и
перемещений, каждое в отдельности, не превосходит
п (Uog2n]+ l)«nlog2n.
В описаниях алгоритмов этого параграфа постоянно
предполагалось, что все элементы данного массива
различны. Алгоритмы могут быть подправлены так, чтобы
освободиться от этих предположений. Несущественно
также, что речь все время шла о числовых массивах.
Этими алгоритмами можно, например, упорядочивать
массивы слов, составляющих некоторый словарь.
Задача 6. Составить алгоритм решения следующей задачи.
Дан числовой массив а^а^. . .<а„ и число Ь. Найти k, равное
п+1, если ап<Ь и равное наименьшему числу т, для которого
Ь<ат в противном случае. Для решения задачи использовать аналог
алгоритма деления пополам.
112
§ 2. Подмножества конечных множеств
1. Перебор подмножеств. Пусть дано некоторое
конечное множество объектов. Занумеровав эти объекты
числами 1, 2, ..., п, можно для некоторых исследований
заменить сами элементы их номерами и считать, что
имеющееся множество — это {1, 2, ..., п). Тогда
непустое подмножество имеющегося множества — это
набор чисел ii, i2, ..., ih, l^/1<i'2<.. .<:ik^.n. Всего
таких подмножеств (включая пустое) — 2". В самом
деле, подмножествам взаимно однозначно
сопоставляются n-элементные наборы (массивы) из нулей и единиц
Ьи Ьг, ..., Ьп, где bt — l тогда и только тогда, когда i
входит в подмножество. Число таких наборов
действительно равно 2".
Рассмотрим теперь некоторый массив объектов
аи ■ ■ •> <V Элементы массива с самого начала
перенумерованы. Массив аи ..., ап обладает 2" подмассивами,
в число которых входит пустой подмассив и
последовательности элементов ati, ai2, ..., a(ft, 1^г'1<гг<-. .<г'А^«.
В некоторых случаях приходится решать задачу выбора
из данного массива одного или нескольких подмассивов,
удовлетворяющих определенному условию. Можно
столкнуться с условием такого рода, что окажется трудным
найти решение более искусное, чем полный перебор
всех подмассивов, сопровождаемый проверкой условия
для каждого из них. Так обстоит дело, например, когда
из данного массива чисел аь ..., ап нужно выбрать
подмассивalt, а!з,..., а,- такой, что значение sin (#,-,+.. .+
+ai ) — наибольшее из возможных.
Вместо функции sin могут быть рассмотрены любые функции,
достаточно сложно изменяющие свое значение при изменении
аргумента. Мы для определенности рассмотрим функцию sin, считая,
что вычисление ее значения либо входит в набор допустимых
операций, либо описано как алгоритм. Нашей главной задачей будет
организация перебора подмассивов.
Решение задачи перебора подмассивов не зависит от природы
объектов массива, но мы, по условию, считаем массив числовым.
В связи с необходимостью перебора всех подмассивов
Данного массива аи ..., ап рассмотрим задачу перебора
всех массивов Ьи ..., Ъп из нулей и единиц. Эти
массивы будут истолкованы как указатели подмассивов
массива аи ..., ап. Если и=6, то 0, 1, 0, 1, 1, О
Указывает на подмассив аг, at, a6. На подмассив аи
113
а2, а4, ав будет указывать 1, 1, О, 1, О, 1. Поскольку
«-элементных массивов из нулей и единиц 2", эти
массивы некоторым образом можно перенумеровать числами
1, 2, 3, ..., 2". Однако удобно массиву 0, 0, ..., О,
который указывает на пустой подмассив, присвоить
номер 0. Поэтому в качестве номеров будем употреблять
числа 0, 1, 2, ..., 2"—1.
Мы пришли к общей постановке задачи перебора
всех подмассивов массива из п элементов. Итак: дано
натуральное п; каким образом можно взаимно
.однозначно сопоставить каждому из чисел 0, 1,2, ..., 2"—1
некоторый я-элементный массив из нулей и единиц?
Хотелось бы получить достаточно простой алгоритм
сопоставления.
Задача 1. Дан массив чисел ах ап. Нужно ли в
алгоритме выбора элементов а,-,, а/2, . . ., а/, таких, что сумма a/,rf-a/2+
-J-. . -Л-сЧу— наибольшая из возможных, производить перебор
всех подмассивов?
2. Десятичная, двоичная и .другие системы.
Рассмотрим вначале задачу, родственную задаче сопоставления
числам 0, 1, ..., 2"—1 массивов Ьи ..., Ьп из нулей
и единиц. А именно, займемся сперва массивами из п
чисел, каждое из которых есть одно из 0, 1,2, 3, 4, 5, 6,
7, 8, 9. Каждый такой массив можно рассматривать как
последовательность цифр в записи целого
неотрицательного числа. Таким образом, каждому целому числу
от 0 до 10"—1 взаимно однозначно может быть
сопоставлен массив его цифр. Если цифр меньше чем п, то
недостающие цифры старших разрядов считаем нулями.
Решение оказалось простым потому, что в качестве
элемента массива допускается любое число, которое
можно записать одной цифрой. Видимо, должно
существовать похожее решение и для массивов из нулей
и единиц. Чтобы подойти к этому решению, исследуем,
как строится обычная запись числа. Если некоторое
неотрицательное целое число записано
последовательностью цифр dh dh-i.. .di, O^.di^.9 (черта надписана,
чтобы не возникло путаницы с произведением), то это
означает, что число равно dh\0k~1+dil-i\0lt~t+.. .+dj.
Таким образом, 10 играет в традиционной записи особую
роль — говорят, что числа записываются в десятичной
системе. По аналогии с десятичной системой можно
рассмотреть другие системы, например двоичную си-
114
стешу. В десятичной системе одной цифрой
изображаются числа от 0 до 10—1=9. В двоичной системе от
0 до 2—1 = 1. Итак, в двоичной системе две цифры 0 и 1.
Число N, записанное в двоичной системе
последовательностью цифр bmbm-i...bu 0<6г<1, должно быть равно
bM2»-i + ba_12»-*+...+bi. (1)
В сумме (1) все слагаемые, кроме, может быть,
последнего, делятся на 2. Так как bi — это 0 или 1, заключаем,
что bi равно остатку от деления N на 2. Частное равно
bm2ffl-2-Hbm_i2ra-3+...+^3. Одним делением N на 2
с остатком мы однозначно определяем последнюю цифру
bi числа N в двоичной системе (остаток) и находим число,
запись которого в двоичной системе есть ЬтЬт-ь . .Ь2
(частное). Эту процедуру можно повторять многократно
и получать поочередно цифры b2, bs, ..., bm. После
деления на 2, определившего Ьт, частное станет равным
нулю.
Запишем 20 в двоичной системе:
20=10x2+0
10= 5x2+0
5= 2x2+1
2= 1x2+0
1= 0Х2+1
Получилось 10100— и действительно, 1-24+0-23+1-2а+
+0-2+0=16+4=20.
То, что человечество пользуется десятичной системой,
исторически связывают с наличием десяти пальцев на
руках. Никакой принципиальной математической
разницы между десятичной и двоичной системами нет. Для
любого натурального q^2 можно рассмотреть q-тную
систему. Цифрами должны изображаться числа от 0
до q—1. Построение записи N в ^-ичной системе — это
представление N в виде суммы wsqs~1+ws-1qs~2Jr- • .+m>i,
O^w^q—1. Процедура построения записи N в q-тной
системе аналогична описанной процедуре для q—2:
нужно последовательно производить деления на q с
остатком.
Задача 2. Записать 20 в <?-ичпой системе для д -3, 4, 5, 6,
7, 8, 9, 10.
Итак, в личной системе используются q цифр. Если
9<10, то это, как правило, арабские цифры. При <?>Ю
115
приходится изобретать недостающие цифры. Рассмотрим
двенадцатеричную систему. В качестве цифр могут быть
использованы 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, а, р\ Запишем
в этой системе 20:
20=1x12+8
1=0x12+1
Получилось 18. Запишем в этой системе 165:
155=12x12+11
12= 1x12+ 0
1= 0X12+ 1
Получилось 10р\
В g-ичной системе можно производить над числами
сложение, вычитание, умножение и деление-
«столбиком» — точно так же, как и в десятичной системе. Нужно
лишь помнить, что перенос в старший разряд происходит
тогда, когда количество единиц рассматриваемого
разряда превосходит q—1.
Сложим в двоичной системе числа 10100 и 101:
,10100
+ 101
1100Г
Перемножим эти же числа:
v 10100
2 loi
, 10100
+10100
1100100
Задача 3. Выполнить над рассматриваемыми числами
операции вычитания и деления.
Если выбрана g-ичная система, то 1, 10, 100, ...
суть записи чисел q°, q1, q2, ... Умножение на q числа,
записанного в g-ичной системе, равносильно
приписыванию нуля. Признак делимости: число делится на q
тогда и только тогда, когда в g-ичной системе оно
оканчивается нулем.
Задача 4. Сколькими нулями оканчивается записанное
в 9-ичной системе число 100!, если q=2, 5, 10? (100 — запись в
десятичной системе).
116
Пусть N — натуральное число, записанное в ^-ичной
системе. Сколько цифр в записи числа N7 Числа,
записываемые k цифрами,— это числа из диапазона от <7*~*
до qk—1. Нас интересует число k такое, что qk~1^N^.
^qk—1. Это можно записать и так: qk~1^.N<^qk.
Отсюда k— l^logqN<k и k— l = [log,tf], fe=[log,yV]+l.
Задача 5. Сколько цифр в числе 2100, записанном в ^-ичной
системе, если q=2, 5, 10?
Указание, lg 2=0,30103...
Уменье записывать число в двоичной системе
позволяет ответить на поставленный в конце предыдущего
пункта вопрос. Числу i из диапазона от 0 до 2"—1 мы
сопоставляем массив цифр из записи числа i в двоичной
системе. Если цифр меньше чем п, то в старших
недостающих разрядах помещаем нули.
Пусть я=5; тогда числу 0 будет поставлен в
соответствие массив 0, 0, 0, 0, 0, числу 3—0, 0, 0, 1, 1, числу
20—1, 0,1, 0, 0, числу 31—1, 1, 1, 1, 1.
Задача 6. Какой массив будет сопоставлен числу 30?
Какому числу будет сопоставлен массив 1, 1, 0, 1, 1?
Приведем алгоритм построения массива цифр
данного числа N в двоичной системе. Для осуществления
этого построения требуется находить частное и остаток
от деления на 2. Найти частное и остаток можно, если
имеются, например, четыре основные арифметические
операции и операция целой части. Тогда частное есть
[NI2], а остаток — N—2 [NI2].
А: Дано N> 0. Вычислить blt &2, ..., Ьт такие, что
0<6,.<1, Ьтф0, iV=ft«2—i+&»-i2—»+...+61;
А\: «: = 1;
А 2: повторять начало
s: = [jV/2]; bi: = N—2s;
N:=s; t: = t + l
конец
пока не N = 0
Замечание. Применение этого алгоритма
обеспечивает построение ровно стольких элементов массива,
сколько цифр в числе N в двоичной системе. Если нужно,
чтобы в массиве было ровно п элементов и N<.2n, то
для заполнения недостающих старших разрядов нулями
можно условие окончания N=0 заменить условием i>n.
Задача 7. Запись числа N в десятичной системе есть 4944.
В какой системе его записью является 6703?
117
3. Алгоритм перебора подмассивов. Теперь есть все
еобходимое, чтобы решить задачу выбора из массива
1, ..., ап такого подмассива alt, а,-а,..., щ , что значение
in(a,-i+G/2+. • -+flu) — наибольшее из возможных. Ус-
овимся считать, что сумма элементов пустого подмас-
ива равна нулю.
Задача может быть решена в 2" этапов. На каждом
тане исследуется некоторый подмассив исходного мас-
ива. После очередного этапа становится известным
аибольшее значение из всех синусов сумм исследован-
..ых подмассивов. В цикле перебираем все / из интервала
т 0 до 2"—1 и для каждого из них строим массив цифр
двоичной системе. С помощью'каждого такого массива
ыделяем из аь ..., ап подмассив, члены его суммируем
. вычисляем синус суммы. Этот синус сравниваем с
олученным на предыдущем этапе значением.
Нетрудно здесь заметить дефект: рассмотрев некото-
ое /, которое переводилось в двоичную систему, нужно
ычислить/+1 — очевидно, в той системе, в которой
проводит вычисления выполняющий алгоритм,— а затем
.еревести полученное значение опять в двоичную си-
тему. Гораздо естественнее от / в двоичной системе
рямо переходить к /+1 в двоичной системе. Для этого
ужно по массиву цифр числа / уметь строить массив
...ифр числа /+1. Это построить несложно. Нужно
просматривать массив, начиная с цифр младших разрядов
о тех пор, пока не встретится нуль. .Пока идут
единицы, их нужно заменять нулями, а первый нуль
заменить единицей и все закончить. Это не что иное,
как перефразировка правила сложения «столбиком».
При таких действиях не потребуется переводить числа
из системы в систему.
А': Массив &,-, ...,Ь„ из нулей и единиц такой,
что Ьп .. . 6j < 2" преобразовать в массив цифр
числа Ьп ... fcj-f-1 (в двоичной системе);
А'\: /г: = 1;
А"2: пока bk = 1 выполнять начало Ьк: = 0; k\ = k + 1
конец
Л'З: ftk: = l
Будет полезен еще один алгоритм:
S: Вычислить s—сумму тех ah для которых Ъ, — 1;
SI: s:=0;
S2: г:-=1;
U8
S3: пока i^.n выполнять
начало
если Ь{ = 1, то s: = s -f a,-;
i: = i + 1
Не желая использовать в основном алгоритме приказ
/:=/+1, чтобы не дублировать уже проделанные в
двоичной системе действия, мы вообще исключим / из
алгоритма. Будем рассматривать массив Ьи Ьг, ..., Ьп+1,
состоящий из л+1 элемента. Указывать на подмассив
массива сц, ..., ап будут первые п элементов, a bn+i
послужит для контроля за окончанием всего счета:
как только выполнится Ьп+1=\, нужно будет все
закончить (/=2").
М: Дано п и числовой массив аь ..., ап.
Из всех значений sin («/, + «/„ 4- • • • +oik),
1 ^ «J < .. . < ik <[ п выбирается наибольшее т.
Сумма пустого подмассива считается равной
нулю;
Ml: v. = 2;
М2: повторять начало bv:~0; v:—v-\-\ конец
пока не и = п +2;
МЗ: 6Х: = 1;
ЛИ: m: = 0;
Mb: пока bn+i — 0 выполнять начало
вычислить s с помощью
алгоритма S;
s: = sin (s);
если s > m, mom:—s;
изменить bt, ..., bn+1
с помощью
алгоритма А'
конец
Задача 8. Как надо изменить алгоритм, если из условия
задачи удалено замечание о том, что сумма элементов пустого
подмассива равна нулю, и такой, подмассив необходимо исключить из
рассмотрения.
Ответ. Шаг Ml заменяется на
М\: v:=3,
шаг /ИЗ — на
А13.1: V=0;
УИ3.2: &2:=1;
шаг /И4 — на
М4: т:—sin fa)
Задача 9. Упростить алгоритмы, сделав массив 6,, Ьг, ...
• • ■, Ьп + 1 логическим. Число 1 заменяется на Я, 0— на У/.
119
§3. Бектрекинг
Перебор всех подмассивов данного массива аи • • -, ап
требует рассмотрения 2" возможностей. Значение 2"
при увеличении п быстро растет. Анализ особенностей
условия, которому должен удовлетворять искомый
подмассив, часто позволяет сократить перебор
возможностей.
1. Тупики. Чтобы определить л-элементный массив
из нулей и единиц, который выделяет подмассив
массива аи ..., ап, нужно про каждый элемент аи ..., ап
решить, принимается он в подмассив или нет. Может
возникнуть следующая ситуация: относительно
элементов аи ..., a,, i<Ln, приняты какие-то решения,
после этого обнаружилось, что как бы мы ни
распоряжались остальными элементами, нам все равно не удастся
получить подмассив, удовлетворяющий поставленному
условию. В этом случае можно исключить из
рассмотрения 2п~{ подмассивов, первые элементы которых
выбраны из числа аи ■ ■ ■, сц в соответствии с принятыми
решениями. Например, дан массив положительных
чисел аь ..., ап и положительное число М. Требуется
построить подмассив a{i, а/а, ..., щ такой, что a^-\-atj-\-
+...+а( =тИ. Если уже по каким-то соображениям
выбраны числа ait, ah,..., щ и сумма этих членов больше
М, то попытка подобрать к уже выбранным элементам
еще несколько из щ +\, щ +2, ..., ссп так, чтобы,
общая сумма была равна М, заведомо обречена на
неудачу.
В общем виде задача может быть поставлена
следующим образом. Пусть среди всех «-элементных массивов
из нулей и единиц требуется отыскать удовлетворяющие
фиксированному условию. Пусть условие таково, что
некоторые более короткие массивы являются
тупиками — они не могут быть превращены в искомые
массивы дописыванием нескольких элементов. Пусть
имеется алгоритм, который позволяет распознавать хотя
бы некоторые тупики (т. е. может быть применен к
любому массиву из нулей и единиц, содержащему менее п
элементов," и в случае, если результатом применения
будет И, массив заведомо является тупиком). Требуется
использовать имеющийся алгоритм для возможно
большего сокращения перебора.
120
В предыдущем параграфе обсуждался способ
перечисления всех /г-элементных массивов из нулей и
единиц.
Например, порядок, в котором предлагалось
перечислять все трехэлементные массивы, был таким:
о, о, о
о, о, 1
О, 1, О
0, 1, 1
1. О, 0 (1)
1, 0, 1
1, 1, О
1, 1, I
Предложенный порядок можно охарактеризовать как
словарный — если рассматривать перечисляемые
массивы как слова в алфавите {0, 1}, считая, что 0
предшествует 1, то именно в таком порядке массивы попадут
в словарь.
Обычно в словарях встречаются слова разной длины.
Наряду с(1) можно рассмотреть последовательность
О
О, О
О, О, О
О, 0, 1
О, 1
О, 1, 0 *
0, 1, 1 (2)
1
1, О
1-, О, О
1, 0, 1
1, 1
1, 1, О
1, 1, 1
Короткие массивы (с длиной меньшей п) тоже
интересуют нас: именно к ним следует применять алгоритм
распознавания тупиков.
Словарный порядок обладает тем свойством, что
массивы, начинающиеся с одной и той же группы цифр,
иДут подряд. Поэтому, если какая-то группа цифр
пРизнана тупиком, то из последовательности массивов
121
могут быть исключены несколько подряд идущих
массивов. Если какой-то из коротких массивов не оказался
тупиком, то к нему приписывается 0. Так, если 1, 0—
не тупик, то дальше рассматривается 1, 0, 0. Если
зашли в тупик или столкнулись с массивом длины п,
то дальше надо заняться массивом, который
Г не является удлинением рассмотренного массива;
2° расположен в словаре дальше, чем рассмотренный
массив;
3° из всех массивов, удовлетворяющих Г, 2°,
встречается в словаре первым.
Например, если 1,0 — тупик, то надо перейти к 1, 1.
От тупика 1, 1 переход к следующему массиву невоз-,
можен; перебор прекращается. Если л=3 и тупиками
являются 0, 0 и 1, то предложенный принцип перебора
диктует последовательное рассмотрение массивов:
0,
0, 0
0, 1
0, 1, 0
0, 1, 1
1
Отсеиваются только заведомо негодные варианты,
и нужные массивы длины п следует искать среди двух
массивов: 0, 1, 0 и 0, 1, 1.
2. Обратное прослеживание. Уточним стратегию
поведения в ситуации, когда попался тупиковый массив
с числом элементов <; п, или когда число элементов
есть п.
В: В массиве bt, ..., bn, для элементов которого
допускаются значения 0, 1, рассматривается
группа k первых элементов (k^n) такая, что
она является тупиком или k — n. Требуется
изменить значения начальных элементов и
переменной k так, чтобы получилась новая группа
элементов Ьг, ..., bk, которую нужно
рассматривать вслед за данной группой.
В\: пока bk=\ /\k^l выполнять k:—k—1;
В2: 'если k~^\ то Ък: — \
Получается новая группа элементов 6,, ..., Ьъ
причем значения элементов bh+l, ..., bn не представляют
интереса, некоторые из этих элементов могут вовсе
122
не иметь значений. Если тупиковая группа— 1, 1, ..., \t
то следующую группу построить нельзя; сигналом об
этом будет 6=0.
Итак, наряду с добавлением новых цифр при
продвижении от начала к концу, время от времени
возникает обратное прослеживание цифр. Английское слово
бектрекинг (the backtracking — обратное '
прослеживание) дало название перебору в словарном порядке
некоторых слов или массивов, при котором не
рассматриваются слова или массивы, являющиеся удлинениями
замеченных тупиков.
Задача 1. Пусть в результате рассмотрения группы цифр
О, 1, 1, 1, 1, 1, 1 обнаружено, что это — тупик. Какую следующую
группу начальных цифр нужно рассмотреть?
Перебор массивов с помощью бектрекинга может
производиться, в зависимости от цели перебора, либо
до исчерпания всех массивов, либо до возникновения
первого массива, удовлетворяющего поставленному
условию.
Задача поиска в массиве положительных аи ..., ап
какого-нибудь подмассива с суммой элементов, равной
положительному числу М, позволяет прекратить
перебор с появлением первого такого подмассива. Если бы
требовалось найти все такие подмассивы, или
подсчитать их количество, то перебор продолжался бы до
исчерпания всех возможностей.
Опишем С — общий алгоритм поиска среди
«-элементных массивов из нулей и единиц такого, который
обладает некоторым фиксированным свойством. Будем
предполагать, что в нашем распоряжении имеется
алгоритм Т, с помощью которого исследуются k первых
элементов (k^ji) массива Ьи ..., Ьп. Значениями
Ьъ ..., bh должны быть единицы и нули. В результате
применения Т вырабатывается значение И, если k<.n
и Ьи ..., Ьи — тупик или если k—п и blt ..., Ьп не
обладает нужным свойством.
Вспомогательная переменная t в алгоритме С имеет значение И,
если рассматриваемый в данный момент массив blt . . ., Ь^
тупиковый. Она используется с тем, чтобы сократить число обращений
к алгоритму Т.
С: Дано п. Используя алгоритм Т, построишь
массив из нулей и единиц blt ...,bn такой,
что применение Т к blt ..., Ь„ дает Л;
123
CI: fe: = 0;
C2: t-.^Л;
СЗ: пока t V k < n выполнять
если ~] t то начало
ft:=fe+l; fc»:=0;
*: = T(fc)
конец
иначе начало
изменить blt .. ., bk
no алгоритму В;
если k = 0 то выход;
t:=T(k)
конец
Задача 2. При каких условиях оканчивается выполнение
алгоритма С?
3. Задача о сумме. Используя бектрекинг, решим
задачу нахождения такого подмассива данного массива
положительных чисел аъ ..., ап, сумма элементов
которого равна данному положительному М.
Видимо, будет полезным алгоритм вычисления по
данному k (k^.n) суммы тех элементов а} (1^/^fe), для
которых Ь}=1. Подобные суммы'нужны, в частности,
для распознавания тупиков. Такой алгоритм мало бы
отличался от алгоритма S из предыдущего параграфа:
нужно только добавочно включить в данные число k
и изменить условие в приказе цикла. Будем считать,
что этот алгоритм составлен и назван S'.
Чтобы в решении задачи о сумме использовать общий
алгоритм С из предыдущего пункта, необходимо
описать алгоритм Т. Опираясь на 5', это сделать легко:
Т: По п, k и Ьъ ..., bk определить, верно ли, что
k<Cn и Ьи ..., bk — тупик, или что k—n и сумма
соответствующих элементов массива а±, ..., ап
не равна М. Если верно, то г:=И, иначе г:=Л;
71: вычислить s по алгоритму S';
Т2: z:= (s>M)V (k=nAs¥=M).
Теперь алгоритм С полностью решает задачу о сумме.
Но решение следует признать не вполне удачным:
слишком много обращений к алгоритму S'. Чтобы
сократить число обращений, полезно обзавестись
массивом s0, sx, ..., s„ таким, что Sj(l^a^fe) представляет
собой сумму тех элементов aj из числа а±, ..., at, для
которых bj=l; назначение s0 — вспомогательное. Мас-
124
сив s0, Si, ..., s„ будет рассматриваться вместе с
массивом Ьи ..., Ьп и числом k, при этом обращаться к
алгоритму S' не придется, так как нужная сумма есть sh.
Алгоритм С в этом случае преобразуется в
алгоритм С":
С: Дано п, массив положительных чисел аи ..., ап
и положительное М. Построить массив из
нулей и единиц Ьи ..., Ьп такой, что сумма
тех «г, для которых 6г=1, равна М;
С'\: *:=0,
С'2: /:=Л;
С'З: s0:=0;
С'4: «о/са t\Jk<n выполнять
если ~| ^ то начало
k:=k+l; bk:=0; sft: = sjfe_1;
/: = (£ = «) Л (sft=^M)
иначе начало
изменить bit ..., bft н ft
по алгоритму В;
если k = 0 то выход;
конец
За устранение повторений в вычислениях сумм мы
расплатились введением дополнительного массива, но
можно избежать этого, так как, если известны s„, s1; ..., sk,
то по ним однозначно могут быть определены Ьи ..., bh.
В самом деле,
( 1, если st > S;^lt
l~ \ 0, если s,- = s,-^.
Значит, можно оперировать с одним массивом
s0, ..., sn. Нужно переделать алгоритм В следующим
образом:
fl'l: k:=m;
В'2: s0:=0;
В'З: пока k~^\ f\s£>sh-i выполнять k:=k—1;
S'4: если k^l mo sk:=sk-1+ak
Теперь нетрудно написать новый алгоритм С". Но
если просто изгнать массив Ъх, ..., Ьп из алгоритма С",
то результатом применения нового алгоритма придется
считать si, ..., sn (при &>0). Можно добавить еще не-
125
сколько шагов, которые изменят значения slt ..., sn
так, чтобы они стали единицами и нулями, как это
требуется условием задачи.
Задача 3. Описать алгоритм С" в соответствии с
предложенным планом.
Задача 4. Описать алгоритм вычисления количества всех
подмассивов с суммой элементов, равной М-
Задача 5. Предположим, что в алгоритмах можно
использовать приказ печать (d), где d — это или обозначение массива,
или переменная. Выполнение этого приказа приводит к тому, что
где-то в условленном месте выписывается (печатается) значение
элементов массива или значение переменной. Никаких значений
этот приказ не изменяет. С привлечением этого приказа составить
алгоритм печати всех сочетаний из п элементов по т. Каждое
сочетание задается n-элементным массивом из нулей и единиц, в
котором единиц ровно т.
Задача 6. Из всех сочетаний (см. предыдущую задачу)
сформировать матрицу (см. задачу 6 гл. III, § 5) с п столбцами и
С™ строками так, что каждая строка — это некоторое сочетание
(для каждого i из диапазона от 1 до С™ элементы ец, е,-2 е;п суть
нули и единицы, единиц ровно т штук) и все строки различны.
§ 4. Восемь ферзей и лабиринт
1. Восемь ферзей. Принимать или нет данный элемент
массива в подмассив? Два возможных исхода этого
решения мы обозначали 1 и 0, и совокупность исходов
давала запись некоторого неотрицательного целого
^2"—1 в двоичной системе.
Встречаются задачи, которые, как и задача выбора
подмассива, требуют многократного принятия' решений,
но возможных исходов каждого решения оказывается
больше двух.
Рассмотрим задачу о 8 ферзях. На обычной
шахматной доске надо расставить 8 ферзей так, чтобы они не
угрожали друг другу. Если ферзи расставлены и
условие задачи выполнено, то в каждой вертикали
находится ровно один ферзь. Все, что требуется сделать,—
это решить для каждой вертикали, на каком именно из
ее полей помещается ферзь. Априори каждое такое
решение может иметь 8 исходов.
Если пронумеровать горизонтали снизу вверх
цифрами от 0 до 7, то любое расположение ферзей, при
котором в каждой вертикали расположен ровно один
ферзь, может быть изображено последовательностью
из 8 цифр от 0 до 7. Например, расположение, которое
126
представлено на рис. 36, изображается
последовательностью 24065137. Это расположение не удовлетворяет
условию задачи, так как ферзи в 1-й и 3-й вертикалях
угрожают друг другу.
Нетрудно заметить, что любому такому
расположению предложенным способом однозначно сопоставляется
некоторое целое число в восьмеричной системе.
Сопоставляемые числа заполняют промежуток от 0 до 77777777.
Последнее число в восьмеричной системе изображает
88—1. Это показывает, что всего таких чисел 88. Мы
получили и путь решения задачи: перебирать числа в
восьмеричной системе от 0 до 88—1 и для каждого из
них вцяснять, изображает ли
оно требуемое условием
задачи расположение.
Восьмеричное число
можно представлять массивом
цифр Ьи ..., Ь8. Перебор
осуществляется поэтапным
наращиванием числа на 1.
Задача 1. Описать
алгоритм перехода от blt . . ., 68 к
массиву цифр числа, которое на 1
больше исходного. Предполагать,
что исходное число <88—1.
ш
чз
mm
-а
ы
&,
ж
№.
55
Рис. 36.
Удовлетворяет ли некоторое расположение ферзей
условию задачи, имеет смысл проверять
последовательным рассмотрением вертикалей. Для каждой вертикали
нужно установить, не угрожает ли ее ферзь какому-
нибудь из ферзей в предыдущих вертикалях. Как только
обнаруживается, что ферзь в i-й вертикали угрожает
какому-то из ферзей в вертикалях 1, 2, ..., i— 1,
проверку можно закончить и дать отрицательный ответ.
Если дошли до восьмой вертикали и не обнаружили
угрожающих друг другу ферзей, то дается
положительный ответ.
Предложенный план нетрудно реализовать, но уже
проведенное поверхностное обсуждение обнаруживает
его слабые места. Коль скоро замечено, что при данном
расположении ферзь в i-й вертикали угрожает ферзю
в какой-то вертикали с меньшим номером, то можно
не заниматься далее не только этим расположением,
но и всеми теми, которые предполагают ту же самую
127
расстановку ферзей в первых I вертикалях. Сразу можно
отказаться не от одного, а от 88-' расположений.
Возникают тупиковые ситуации. Обнаружив тупик, будем
поступать, как в предыдущем параграфе — переходить
к некоторой другой группе (количество цифр которой
не больше, чем в обнаруженном тупике).
Если уже установлены не угрожающие друг другу
ферзи в первых i—1 вертикалях и при добавлении ферзя
в j-ю вертикаль на нижнюю, нулевую, горизонталь
выяснено, что новый ферзь угрожает какому-то из
предыдущих, то продвигаем ферзя на одно поле вверх
и вновь проверяем, получилось ли допустимое
расположение. Если нет — передвигаем ферзя еще на одно
поле вверх и т. д. до последней горизонтали. Пусть для
этого ферзя не нашлось ни одного подходящего места.
Тогда удаляем его с доски и начинаем подыскивать
новое место для ферзя из i—1 вертикали, передвигая
его вверх. Если места для него не нашлось, то снимаем
и его и переходим к вертикали с номером i—2 и т. д.
Ферзи добавляются по возрастанию номера
вертикали, а когда дело заходит в тупик, вертикали
рассматриваются обратным прослеживанием. Таким образом,
эта задача тоже решается бектрекингом.
На рис. 37 приведено 26 расположений ферзей (в
некоторых из них заняты не все вертикали), которые
возникают при попытке решить бектрекингом задачу
о 4 ферзях на доске 4x4.
Задача 2. Взять шахматную доску и 8 каких-нибудь фигур.
Считая все фигуры ферзями, осуществить расстановку 8 ферзей,
применить разработанный метод.
Для придания алгоритму большей универсальности
будем считать, что ферзей п штук, а доска имеет размеры
пХп. Мы не станем предполагать, что решение заведомо
существует. Если решение существует, то оно будет
представлено массивом Ьи ..., Ьп, каждый элемент
которого — это целое число от 0 до п—1. Значение
переменной k будет указывать, сколько ферзей
установлено в данный момент на доске (сколько первых
элементов массива Ьи ..., Ьп занято). Если после
окончания выполнения алгоритма окажется", что fe=0, то,
значит, нужного расположения не существует.
Мы возьмем за образец алгоритмы В и С из
предыдущего параграфа. Нужно внести некоторые изменения,
128
22/,
ш
%
%
2//
V2
У/л
УУ/
2/,
ш
22/
2/у
й
'&
4
%.
чШ
ш
%
т
Щ
22/
22/
ш
%
/,"■
Г~М
щ
ш
т
<&
22,
У
шт
Ж
в)
1
ш,
т
№
м
ш
т
22/
22/
Ш.
щ
■•$4
/¥/,
'У/у
22/
■мь
22/
22
т
У/,
2//
V2
***sT
ш
ш
ш
d
Т'
ш
%
ш
Ж)
22/
2/
/У"?',
ш
У2/
2//У
-&
ш
ш
m
ш
ш
/V/
ш
ш
m
•&>
§
УУ/
22.
ь
3)
ш
ш_
Ш"''?.
"&
щ
Н)
m
ш
%.
m
щ
•щ
m
У/л
■щ
Р
Л)
ш
УГГ<
' (У/
Щ
'
ш
"©■
У/у/
У/'
У
р
m
щ
щ
УУ/
УУ/
•^
ш
m
m
УУ/
22/
а)
m
щ
ш
Щ
'2//
2/У
^
ш
ш
i
М)
m
УХ
m
m
m
ш
ш
/У/
22у
ш
V7&\—
УЛ.
•м.
£L
УУ/,
ш
ш
'4
ш
222
22,
Щ
m
4Jm
■&
Ф
Ж
tr
m
В.
V)
щ
ш
ш
ш
ш
и)
у)
^
W
ф)
'22у
2У
tt
'22
22
m
'2Уу
/уу<
/// /
ш
У/У
•л m
V
ш
^Ш.
&у
^и
ш)
щ)
ь)
Рис. 37.
^ С. А. Абрамов
129
потому что для значения каждого элемента Ъ% имеется.
п возможностей.
Bck: В массиве Ьи ,,., Ьп, для элементов которого
допускаются значения О, 1, ..., п—1,
рассматривается группа первых k элементов (&<л),
являющаяся тупиком или k=n. Требуется
.изменить значения начальных элементов и
переменной k так, чтобы получилась новая
группа элементов Ьи .,., bk, которую нужно
рассматривать вслед за данной группой;
Bck 1: пока bh—n—\/\\С&\ выполнять k:—k—1;
Bck2: если k^l то bk:=bk+l
Алгоритм расстановки ферзей назовем Ф. Он будет
использовать алгоритм Т (k) — логическую функцию,
значение которой дает возможность узнать, верно ли,
что какие-то из ферзей в первых k вертикалях угрожают
друг другу.
Ф: Дано п. Построить массив Ьи Ь2, ■.., Ьп, каждый
элемент которого есть число от 0 доп—1,
указывающее место ферзя в очередной вертикали.
Ферзи не должны угрожать друг другу (см.
текст);
Ф\: k:=*Q;
Ф2: и=*Л;
ФЗ: пока t\]k*=n выполнять
если ~] t то начало
конец
иначе начало
изменить blt ..., bk и k по
алгоритму Bck;
если k = 0 то выход;
t:=T(k)
конец
Алгоритм Т применяется для исследования blt ..., bk
только в таких случаях, когда Ьи ..., bk-i задает
расположение неугрожающих друг другу ферзей в
первых k—1 вертикалях. Это позволяет сделать его описание
простым:
Т: Дано k. Требуется определить, задают ли числа
&i, ..,, bh расположение неугрожающих друг другу
ферзей в k первых вертикалях. Считается, что
ферзи в первых k—1 вертикалях не угрожают
друг другу. Если все ферзи не угрожают друг
130
другу, то г должно получить значение Л иначе —
Я;
TU *:=-!;
Г2: г:=-Л;
ГЗ: пока i < /г выполнять
если ~\{bi = bk\f\bk—bi\'*=k — i)
то i: = t + l
иначе начало г: = И; выход конец
Задача 3. Что означает услов'ие 6j=&/sVl&ft—6,-|=й— If
Задача 4. Используя приказ печать (см. задачу 5
предыдущего параграфа), составить алгоритм печати всех расположений
ферзей на доске пхп, удовлетворяющих условию задачи о ферзях.
Задача 5. Используя приказ печать (см. задачу 5
предыдущего параграфа) составить алгоритм печати всех перестановок
чисел 0, 1, 2 п—1.
Указание. Все перестановки чисел 0, 1, 2, . . ., и—1
являются решениями задачи о п ладьях на доске пхп (по аналогии
с задачей о п ферзях).
2. Лабиринт. Лабиринт— это система комнат,
некоторые из которых соединены коридорами. Пример
лабиринта дан на рис. 38. На этом рисунке комнаты
Рис. 38.
занумерованы числами от 1 до 16. Классическая задача
лабиринта — определение пути, соединяющего две
комнаты лабиринта. Если принять, что находящийся в
лабиринте способен отмечать пройденные коридоры, а в
случае надобности — проделать в обратном порядке
часть пройденного пути, то можно предложить такой
способ обхода комнат, при котором рано или поздно
встретится любая комната, в которую вообще можно
попасть.
В ситуации, когда выполнены сформулированные
предположения, находился Тезей, разыскивавший в
5*
131
Критском лабиринте Минотавра. Отмечать пройденные
коридоры и прослеживать свой путь в обратном порядке
он мог благодаря нити, данной ему Ариадной.
В задаче о лабиринте, как и в задаче о ферзях
требуется многократно делать выбор из нескольких
возможностей. Но раньше число возможностей было
постоянным, в задаче о 8 ферзях, например, это число было
равно 8. Находящемуся же в комнате лабиринта
приходится решать, в какую из ближайших комнат ему
пойти, а количество выводящих коридоров,- вообще
говоря, меняется от комнаты к комнате. Однако все это
не является препятствием для применения бектрекинга.
Для простоты будем считать, что комнаты
перенумерованы последовательными числами и попавший в комнату
видит номера соседних комнат. Общий план таков: при
продвижении вперед всегда входить в новую комнату с
возможно меньшим номером (нить сматывается). Если
при таком движении был сделан вход в тупик, или в
комнату, по которой уже прошел путь, то нужно идти
назад в прежнюю комнату (нить наматывается), а оттуда
войти в комнату со следующим по величине номером,
из числа тех, через которые еще не прошел маршрут.
Если последнее невозможно, то нить опять
наматывается и происходит еще один возврат и т. д.
В соответствии с этим планом, поиск пути в
лабиринте на рис. 38 из комнаты 1 в комнату 16 будет
развертываться так (мы выписываем после каждого этапа
последовательность номеров тех комнат, через которые
проходит нить):
1, 2
1.
1,
1,
1,
1,
1,
1,
1,
1,
I,
1,
1,
3
3, 10
со со"
3, 11
3, 11
3, 11
3, И
3, 11
3, 11
3, 11
3, 11
8
8, 1
8
8, 7
8, 7, 6
8, 7, 6, 1
8, 7, 6
8, 7
132
1, 3, 1
1, 3, 1
1, 3, 1
1, 3, 1
1, 3, 1
1, 3, 1
1, 3, 1
1, 3, 1
, 8
, 12
, 12,
, 12,
, 12,
, 12,
, 12,
13
13,
13
13,
13,
14
15
15, 16
Задача 6. Выбрать какую-нибудь иную нумерацию комнат 2,
3, . . ., 15 и вновь решить задачу.
Дойдя до тупика или до уже пройденной комнаты,
маршрут бракуют — его укорачивают на один этап.
После этого возврата можно быть уверенным, что:
1° в дальнейшем иногда не получится маршрут,
являющийся продолжением забракованного;
2° не исключаются из дальнейшего рассмотрения
никакие другие маршруты, кроме уже рассмотренных и
являющихся продолжениями забракованных.
Таким образом, предложенный метод действительно
является вариантом бектрекинга.
Теперь наша цель — рассмотрение деталей алгоритма
поиска пути в лабиринте. Применение алгоритма к
данному описанию лабиринта должно обеспечивать
получение маршрута в форме последовательности номеров
комнат.
В описании лабиринта для каждой пары номеров
комнат i, j нужно зафиксировать, соединены комнаты
коридором или нет. Распространенная форма записи
такого рода данных — это таблицы из п строк и п
столбцов {п — число комнат). На пересечении г'-й строки и
/-го столбца указывается, можно ли попасть из t-й
комнаты в /-ю (0 или 1). Таблицы квадратные и просто
прямоугольные встречаются в математических задачах
весьма часто. Можно сказать, что необходимость в таблице —
явление не менее частое, чем необходимость в конечной
последовательности, т. е. в том, что мы до сих пор
называли массивом. Мы уже встречались с таблицами (см.
задачу 6 гл. III, § 5 и задачу 6 предыдущего параграфа
настоящей главы). Элемент таблицы задается
обозначением таблицы с двумя индексами, например а12, bi5,
са> dt+sp и т. д. Индексы, когда это не вызывает
недоразумений, запятой не разделяются. Значение первого
индекса дает номер строки, значение второго — номер
133
столбца. Итак, мы будем рассматривать еще один вид
переменной — переменную с двумя индексами.
Переменные с одним индексом образуют одномерный массив,
или, как говорят, вектор. Переменные с двумя
индексами — двумерный массив, или, как говорят, матрицу.
Задача 7. Дана числовая матрица
("", Г. *".).
\ami s.. атп/
Составить алгоритм вычисления чисел bi Ьт таких, что 6/
есть сумма элементов t'-й строки матрицы.
Лабиринт, данный на рис. 38, можно представить
матрицей
СО 1 1 1 1 1 0 1 0 0 0 0 0 0 0 0\
1000000000000000
1000000001100000
1 00000001 0000000
100000000000 0 0 00
1000001000000000
0000010100000000
1000001000100000
0001000000000000
0010000000000000
0010000100010000
oooooooo-ooioiooo
00000000000101 1 1
0 000000000001000
0000000000001001
,0 000000000001 01 О,
По этой матрице можно, например, установить, что 10-я
комната соединена с 3-й: третий элемент десятой строки
есть 1. Видно также, что 10-я комната не соединена
с 4-й (соответствующий элемент равен нулю). Если всю
матрицу назвать а, то упомянутые условия
записываются о10 з=1, а1В 4=0.
На таком способе представления лабиринта мы и
остановимся, хотя он не очень экономен.
Ситуация, в которой надо прибегать к обратному
прослеживанию, распознается легко. Пусть имеется
массив номеров комнат blt ..., bh, если это тупик, то
либо bk должно совпадать с некоторым из Ьи ..., bh-lt
134
либо в матрице а все элементы аьки аькъ аЬкП, кроме
flV*-i' Равны нулю. Обратное прослеживание по массиву
Ьи .... bh проводится так: делается попытка найти среди
элементов аьк_хък+х, ^_i*ft+a а^_х„ равный
единице. Если единичные элементы имеются, то берется
первый из них — пусть это будет аЬк_хП. Тогда bh:=m.
Если единиц нет, то массив укорачивается на один
элемент и процедура применяется уже к Ьи ..., bh~t
и т. д.
Если массив Ьи ..., bh не является тупиком, 'то к
нему присоединяется еще один элемент bh+i следующим
образом: среди аьки аьк2, ..., abkk-i, аь^+и ..., а„кП
отыскивается первый, равный единице, пусть это аъ т,
тогда bh+i.=m.
Приведенные соображения несложно оформить в
алгоритм.
Задача 8. Применить бектрекинг для решения задачи о
волке, козе и капусте (имеется в виду не составление алгоритма, а
фактическое решение). Возможности выбора перенумеруем так:
взять с собой волка — 1, козу — 2, капусту — 3, ехать одному — 4.
Из всех имеющихся в данный момент возможностей выбирается та,
которая имеет наименьший номер. Тупик в этой задаче возникает,
когда на одном берегу остается волк с козой или коза с капустой,
а также когда повторяется положение.
Занумеровать возможности как-нибудь иначе и повторить
рассуждения.
Задача 9. Переправа рабов и хозяев. Должны переправиться
через реку я рабов и п хозяев. Лодка, которая находится в их
распоряжении, поднимает только двух людей. При перевозке
необходимо следить за тем, чтобы число рабов ни в коем случае не
превышало числа находящихся с ними хозяев, иначе рабы смогут напасть
на хозяев. Написать алгоритм решения задачи для данного п.
Задача 10. Комнаты Критского лабиринта не были
перенумерованы. Каким образом Тезей мог бы упорядочить возможности
продления маршрута на одну комнату?
Ответ. Поиск выхода из комнаты можно, например,
производить, обходя стены комнаты против часовой стрелки (касаясь стены
правой рукой).
§ 5. Графы и деревья
1. Универсальность задачи о лабиринте. Многие^ (если
не все) задачи выбора последовательности действий
могут быть интерпретированы как задачи выбора
некоторого маршрута в ' лабиринте. Рассмотрим вновь
игру «ханойская башня» для п дисков. Пусть колышки
135
занумерованы 0, 1, 2 а диски (сверху вниз) — 1, ...
..., п—1. Тогда каждое число anan-i ... а.у в троичной
системе задает распределение дисков по колышкам —
i-й диск находится на колышке at, и "на каждом из трех
колышков диски располагаются так, что диаметр
убывает вверх. Это взаимно однозначное соответствие между
неотрицательными целыми числами <13и—1 и
распределениями дисков.
Рассмотрим лабиринт из 3" комнат, обозначенных
числами (в троичной системе) от 0 до 3"—1. Коридором
соединены комнаты, которые отвечают позициям игры
«ханойская башня»,
переводимым друг в друга
одним ходом. Игра может
быть интерпретирована как
поиск пути, соединяющего
комнаты 0 и 3й—1 в этом
лабиринте. Если п=2, то
девять комнат лабиринта
соединяются между собой
так, как показано на
рис. 39.
Задача 1. Нарисовать
лабиринт для игры с тремя
дисками.
Для выбора из
множества аи ..., ап некоторого
подмножества надо так или иначе для каждого i—l, ..., п
решить, берем ли мы at. Обозначим, как прежде, 1 и О
решения «брать» и «не брать». Если решения «брать —
не брать» принимаются последовательно для элементов
аь ..., ап, то имеется лабиринт, вроде изображенного
на рис. 40. Появление комнаты «начало» обусловлено
тем, что в самый первый момент не принято ни одного
решения. Требуется найти путь от комнаты «начало»
до одной из отмеченных тремя цифрами комнат. Путь
должен обладать определенным свойством, отвечающим
условию задачи выбора подмассива.
Видно, что задача поиска пути в лабиринте является
довольно универсальной. Для -такого рода задач
принята особая терминология. Обычно говорят не о
лабиринте, а о графе. Граф состоит из нескольких точек,
называемых вершинами, и нескольких соединяющих
136
эТи точки отрезков, называемых ребрами графа.
Изображенный на рис. 39 лабиринт может быть легко
превратен в граф с 9 вершинами и 12 ребрами (рис. 41).
изображенный на рис. 40 лабиринт заменяется графом,
представленным на# рис. 42.
Не имеет значения, соединены ли две вершины
отрезком прямой или кривой линии. Вершины могут быть
Б свою очередь разными способами расположены на
плоскости. Но вопрос, соединены ли две данные
вершины ребром — принципиальный.
Иногда изображение графа на плоскости содержит
точки пересечения ребер, которые не являются
вершинами. Граф с вершинами А, В, С, D, из которых
соединены А и В, В и С, С и D, D и А, А и С, В и D может
быть изображен так, как это сделано на рис. 43. Точка
пересечения BD и АС не является вершиной. Чтобы
избежать недоразумений, будем вершины изображать
кружками. Этот граф допускает и изображение без
пересечений ребер (рис. 44).
Перед тем, как перейти к алгоритмическим задачам
из теории графов, рассмотрим несколько определений.
Граф называется связным, если его любые две
вершины соединены некоторым путем. Все уже
рассмотренные графы — связные. Мы и дальше будем
рассматривать только связные графы, но в качестве
иллюстрации приведем пример и несвязного графа с шестью
вершинами — см. рис. 45.
Состоящий из различных ребер замкнутый путь
называется циклом. В изображенном на рис. 44 графе
циклом, например, является CDBC.
Задача 2. Выписать все циклы графа, изображенного на
рис. 44.
Связный граф, который не содержит циклов,
называется деревом. Пример дерева дает рис. 42.
2. Задачи нахождения пути в графах. Граф часто
описывают матрицей из нулей и единиц, но возможны и
другие способы описания, например описание с помощью
правила, которое дает возможность узнать, с какими
вершинами соединена данная вершина. Именно так
обстоит дело с игрой «ханойская башня».
В зависимости от свойства, которым должен
обладать искомый путь, может потребоваться перебор и
обследование различного числа путей. Для некоторых
137
Начало
Рис. 40.
А 27 А С
Рис. 43. Рис. 44.
Рис. 45.
задач имеется возможность сокращения перебора
бектрекингом, иногда перебор возможностей вообще не
нужен: известно, как двигаться прямо к цели, выбирая
сразу верные ходы (пример игры «ханойская башня»).
Хотя, конечно, «ханойская башня» может быть решена и
бектрекингом.
Исследование условий задачи, которые приводят к
решению, не требующему большого перебора, может
оказаться отнюдь не тривиальным. Похожие на первый
взгляд задачи часто существенно отличаются в том
отношении, что для одной из них удается найти способ
избавления от перебора, а в
другой — нет. Рассмотрим две задачи.
Г Дан связный граф.
Определить в нем цикл, в который
входит каждое ребро графа.
2° Дан связный граф.
Определить в нем цикл, в который
каждая вершина входит ровно
один раз.
Первая задача часто
обсуждается в школьной математичес- Рис. 46.
кой литературе. Она происходит
от задачи о кенигсбергских мостах (см., например,
О. Оре, «Графы и их'применение», «Мир», 1965), в которой
требуется построить цикл указанного типа для графа,
приведенного на рис. 46.'
Решение задачи для этого графа было дано Эйлером:
он показал, что такого цикла не существует. Он же
указал необходимые и достаточные условия существования
решения задачи для произвольного связного графа.
Цикл, в который входит каждое ребро графа,
называется эйлеровым циклом, а граф, обладающий
эйлеровым циклом,— эйлеровым графом.
Теорема. Связный граф эйлеров тогда и только
тогда, когда в каждой его вершине сходится четное число
ребер.
Доказательство. Если существует эйлеров
цикл, то, обходя по нему граф, мы в каждую вершину
входим столько же раз, сколько выходим. Отсюда
немедленно следует необходимость условия. (Итак, граф
на рис. 46 не является эйлеровым.)
Для доказательства достаточности опишем
(неформально) алгоритм построения цикла. Выйдем из какой-
139
нибудь вершины V и будем, пока возможно, двигаться
по графу, не проходя ни по какому ребру дважды,
В каждой вершине сходится четное число ребер, поэтому,
попав в вершину,, можно из нее и выйти. Исключение
составляет исходная вершина V: в ней маршрут
закончится. Если пройденный путь не охватывает все ребра,
то делаем следующее. Фиксируем на построенном цикле
вершину W, из которой выходят не принадлежащие ему
ребра. Если удалить из графа все ребра, попавшие в
построенный цикл (или просто не обращать на них
внимания), то получится «меньший» граф, тоже удовлетво-
Рис. 47. Рис. 48.
ряющий условию теоремы, хотя, возможно, и не
связный. Прежним способом можно найти содержащий W
цикл в «меньшем» графе. Теперь расширим цикл,
построенный первым,— от вершины V до № движемся, как
прежде, дальше обходим новый цикл, дальше — все,
как прежде. Расширять указанным способом цикл можно
до тех пор, пока он не охватит все ребра.
Задача 3. Доказать, что не существует графов с нечетны»
количеством вершин, в которых сходится нечетное число ребер
Не существует, в частности, графа с одной такой вершиной.
Задача 4. Сформулировать необходимые и достаточные
условия существования в связном графе пути (не обязательно
замкнутого), в который каждое ребро входит ровно один раз.
Исследовать графы на рис. 47, 48.-
Получен алгоритм решения первой задачи, который
не требует отсеивания каких бы то ни было вариантов.
Найденный первоначально цикл многократно
расширяется, и при этом ничего не отбрасывается.
Вторая задача первоначально была предложена в
виде головоломки Гамильтоном. Модель додекаэдра
была устроена таким образом, что в вершинах имелись
140
небольцше крючки, а к одной из вершин был прикреплен
конец нитки. Требовалось провести нитку через все
вершины, укладывая ее вдоль ребер и цепляя за крючки.
Плоскостное изображение этой головоломки и
нумерация вершин, определяющая порядок их обхода, даны на
рис. 49.
В общем случае эта задача оказывается намного более
трудной, чем первая. Видимо, до сих пор не известны
ни критерии существования цикла требуемого типа,
ни лучшие, чем бектрекинг, методы его нахождения (если
цикл существует).
Граф, для которого разрешима вторая задача,
называется гамилыпоновым графом, а цикл, который
дает решение,— гамилыпоновым
циклом. J#
3. Организация справочни- ^^FsN.
ка в виде двоичного дерева. У^^ ^>Nv
Имеется массив различных S^\ ^<^nN.
чисел аи . . ., ап. Если для ^yw ft&\ vyf^
разных чисел часто прихо- \\ / \ 11
дится проверять, входят ли \\ /, AII
они в данный массив, то, как \ VrN. s^"] I
известно, имеет смысл упо- \\ ^*Л/ II
рядочить (например, в поряд- \ У? \9 ?ol
ке возрастания) элементы 7^ ■ - Ч?<?
аи . . ., ап. На каждую про- Рис- 4д.
верку по алгоритму деления
пополам тогда будет уходить примерно lpg2n сравнений
элементов массива с числом.
Возможны случаи, когда при отсутствии элемента с
искомым значением и в массиве а*, . . ., ап требуется
внести это значение в массив — добавить к массиву один
элемент. Пусть с помощью метода деления пополам
найдено k такое, что ah<.u<Cak+u то для занесения и в
массив с сохранением упорядоченности потребуется сдвиг
ak+u ah+2, . . ., ап. Хотелось бы придать совокупности
значений аи ..., ап такую структуру, которая позволяла
бы, во-первых, быстро (примерно за \og2n сравнений)
находить элемент с данным значением и, во-вторых, без
особых усилий добавлять новые элементы.
Рассмотрим задачу кодирования конечной
последовательности целых чисел ги z2,..., zm. Пусть дана
функция целочисленного аргумента F (г), которая принимает
Целые значения. Будем называть F (г) кодом г. Пусть
141
способ вычисления F(z) достаточно сложен, и пусть в
последовательности zu z2, . . ., zm имеются частые
повторения значений элементов. Тогда задача построения
значений F(zi), F(z2), .... F(zm) требует для своего
решения ведения списка (справочника) уже найденных
кодов.
Требованиям, которые предъявляются к структуре
такого справочника, удовлетворяет двоичное "дерево.
Временно следует отвлечься от способа представления
совокупностей чисел именно в виде массивов, который
был принят у нас. К детальному описанию алгоритма
мы подойдем позднее.
Дерево называется ориентированным, если на каждом
его ребре выбрано направление. В соответствии с этим
говорят о ребрах, выходящих из вершины и входящих
в вершину. Двоичные деревья — наиболее простые из
всех ориентированных деревьев. В двоичном дереве в
каждую вершину, кроме одной (корня дерева), входит
одно ребро и выходит не более двух ребер. В корень не
входит ни одно ребро. Пример двоичного дерева дан на
рис. 50. Вершина А — это
корень.
Для удобства обсуждений мы
будем располагать двоичные
деревья на плоскости (листе
бумаги) определенным образом. Корень
будет расположен выше других
вершин (как вершина А на рис.
50). Для ребер, выходящих из
любой вершины, имеется две
возможности — влево вниз и вправо
вниз. Может быть использована
только одна из этих возможностей,
обе возможности или ни одной из
них (см. рис. 50).
Процесс построения двоичного дерева идет так:
первое число и его код образуют вершину. Дерево пока
состоит из одной этой вершины. Следующее число,
которое нужно кодировать, сравнивается с числом в вершине,
и если они равны, то дерево не разрастается и код может
быть взят из вершины. Если новое число меньше
первого, то ведем ребро из имеющейся вершины влево вниз,
иначе — вправо вниз. В образовавшуюся вершину
помещаем число и его код.
Рис. 50.
142
Пусть уже построено некоторое дерево. Пусть
имеется число ы, которое нужно закодировать. Сначала
рассматривается число, записанное в самой верхней
вершине. Если оно равно и, то поиск закончен. Иначе
перейдем к рассмотрению другого числа — того, которое
записано (вместе с кодом) в вершине, связанной с
предыдущей ребром и находящейся либо слева внизу, если
число и меньше только что рассмотренного, либо справа
внизу в противном случае и т. д. Процесс завершается в
одном из двух случаев:
Г найдено число, равное и;
2° в дереве отсутствует вершина, к которой нужно
перейти.
В первом случае из найденной вершины извлекается
код числа. Во втором — выясняется, что
рассматриваемое число еще не кодировалось. Если число еще не
кодировалось, то необходимо вычислить F(u), а затем
присоединить к дереву вершину, в которую и записать
и, F(u).
Пусть последовательность, подлежащая
кодированию, начинается с чисел 7, 10, 6, 9, 6. Тогда вначале
дерево будет разрастаться так, как показано на рис. 51.
Ш 7Я7) 7Д7)
\ А .
10.F0Q) QF(6) fQF(tQ) ff/ff)
8,№
Рис. 51.
При появлении числа 6 в качестве 5-го элемента
последовательности его код будет извлечен из уже имеющейся
вершины.
Задача 5. Построить дерево, соответствующее кодированию
конечной последовательности, 7, 10, 8, 7, 8, 17, 5, 10, 4, 8, 6,
6, 20, 4, 17, 0, 9, 6, 3.
Попытаемся вывести число сравнений при поиске
данного значения в дереве. Ясно, что число сравнений не
может превзойти числа вершин, входящих в самый
длинный путь, ведущий по ребрам из корня в какую-то кон-
143
цевую вершину. Если все т элементов данной
последовательности zu z2, • • -, zm расположены так, что Zi<
<z2<. . .<zm, т0 все дерево вытянется в одну линию
(рис. 52) и число сравнений может достигнуть, т. Если
же эти т элементов, как говорят, хорошо перемешаны,
то вершин в каждом из путей, ведущих из корня до
некоторой концевой вершины, будет примерно поровну,
т. е. дерево не будет получаться однобоким, а будет
похоже на дерево с рис. 53. В случае, когда число
вершин m=2s—1, дерево, вроде изображенного на рис. 53,
будет обладать тем свойством, что в каждый путь от
корня до концевой вершины входит s вершин, т. е.
log2(m+l) вершин. В других случаях
тоже можно считать, что среднее число
вершин в пути от корня до концевой
вершины примерно равно величине log2(m+l).
Итак, такой способ организации
справочника предоставляет удобства в случае
о
\
Рис. 62. Рис. 53.
хорошей перемешанности (неупорядоченности) величин
zu z2, . . ., zm. Есть, однако, и неудобства: если мы
хотим описать алгоритм кодирования, то нужно как-
то изображать дерево. Для этого изображения всем
вершинам в процессе присоединения их к дереву будут
даваться номера 1, 2, 3, ... . Если двоичное дерево
имеет k вершин, то все сведения о наличии
направленных ребер могут быть записаны в матрице
/dn d12 • •• dik\
\dai d22 ... dik/
где dlt — номер вершины, расположенной
непосредственно слева внизу от i-й вершины, a d2t — номер
вершины, расположенной непосредственно справа внизу от
1-й вершины. Если du или d2i равно 0, то
соответствующей вершины в дереве пока еще нет. Таким образом, на
изображение двоичного дерева с k вершинами уходит 2k
144
чисел. Если бы мы изображали дерево матрицей из
нулей и единиц, имеющей k строк и k столбцов, то на
описание дерева ушло бы /г2 чисел, причем пришлось бы
еще каким-то образом указывать направления ребер и
корень дерева.
При составлении алгоритма будем иметь дело с
матрицей d, содержащей 4 строки. При этом du и d2l —
номера вершин, связанных с i-й вершиной, d3i, dti
представляют собой число и и его код, записанные в i-й
вершине.
Пусть имеется функция F вычисления кода.
Первоначально составим алгоритм кодирования одного числа:
С: В дереве с п вершинами, представленном
матрицей d (см. выше), найти w—код числа v.
Если числа и его кода в дереве нет, то
вычислить код с помощью F и расширить дерево;
С\: если я —0 то начало
w:=F(v); dn: = 0; d2i: = 0;
d3i:=v; dti: = w, n: = n + l;
выход
конец;
CI: i: = l;
СЗ: повторять начало
■2;
СЛ
сь
С6
С1
С8
С9
пока не i
п: = п+ 1
w:=F(v);
dkj'-^n;
d3n-=v;
din: = w;
d,„: = 0:
если d3i — v mo
начало w:—d4i; выход конец;
/:=i;
если v < d3i mo k: = l иначе k
i:=dki
конец
= 0;
CIO: din:=0
Алгоритм С применим и в случае, когда в дереве
еще нет вершин. Теперь уже ничего не стоит описать
алгоритм построения массива кодов cit ..., ст данных
чисел г, ...,гт:
D: Построение массива кодов;
DI: п: = 0;
D2: i: = l;
145
D3: повторять
начало
построить код w числа zt с помощью
алгоритма С (при этом, может быть,
расширится дерево и изменится п)\
с{: —w,i:=i + l',
конец
пока не i > m
Задача 6. Доказать, что в любом дереве число вершин на 1
больше числа ребер.
Задача 7. Используя утверждение задачи 6, доказать, что
в матрице
fdn d12 ... din\
\d2i d2% t.. d2n/
которая определяет двоичное дерево так, как объяснено в тексте,
имеется ровно я+1 нулевой элемент.
Задача 8. Двоичное дерево вместе с числами и их кодами в
п вершинах задано матрицей с четырьмя строками и п столбцами
так, как объяснено в тексте. Описать алгоритм проверки, верно ли
составлено дерево.
Глава V. ДАЛЬНЕЙШИЕ РАССМОТРЕНИЯ
Будут решены две довольно трудные задачи, а затем
приведены общие элементарные методы анализа
алгоритмов.
§ 1. Подстановки
1. Отображения конечных множеств. Много говорилось
о подмножествах данного конечного множества и о
способах их перечисления. Не менее интересны и важны
задачи, связанные с отображениями одного конечного
множества в другое. Частный случай такого отображения —
отображение множества на себя.
Имеется в виду следующее. Дано некоторое конечное
множество М и функция s, определенная на элементах
множества М и принимающая значения в этом же
множестве. Будем рассматривать случай, когда значения
функции s покрывают все множество. Из конечности
множества М следует, что функция s — это взаимно
однозначное отображение, которое полностью может быть
задано, например, таблицей образов и прообразов.
Перенумеруем элементы множества М числами 1, ...
. . ., п; после этого таблицу, задающую отображение,
запишем в виде
12.,, я—1 п\ /,ч
к h • • • 'я-i W
где iit i2, . , ., /n_i, in — числа 1,2, . . ., п, взятые в
каком-то порядке. Эта таблица показывает, что 1-й
элемент отображается в fi-й, 2-й — в /2-й и т. д. Часто
мы будем забывать о том, что 1, 2, . . ,,п — это лишь
номера элементов множества М, и считать, что М —
это множество {1, 2, . . ., п), т. е. 1, 2, . . ., п — сами
суть элементы множества М.
147
Взаимно однозначное отображение s конечного мно-
кества М на себя называется подстановкой. Будем гово-
ить, что подстановка (1) переводит j в i}, /=1, 2, . . ., п.
Две подстановки множества {1,2, ..., п) считаются
равными, если любое целое / из диапазона от 1 до
п они переводят в одно и то же число. Таким образом,
/1Ч /1 2 ... я —1 п \
подстановка (1) равна подстановке , , ь ,
тогда и только тогда, когда 1± = ки h~K> •••» К~^п-
Различных подстановок множества -{1,2, ...,«}
имеется п\, так как существует именно п! способов
расположения чисел 1, 2, ..., п в нижней строке (1).
Вот все подстановки множеств {1, 2} и {1, 2, 3}
/123\ /'123\ Г123\ (123\ [123\ (123\
\ 1 2 3 У .» \1 3 2/' V2 1 3/ ' \2 3 1 j ' V3 1 2 J * \3 2 1 J*
Вместо «подстановка множества {1, 2,. . ., п}»
говорят также «подстановка порядка я» или «подстановка
п-го порядка».
Задача 1. Отображение s множества {1, 2, 3, 4, 5} задано
соотношением s(i)=ocrnamoK(3i, 5)4-1. Убедиться, что это
отображение взаимно однозначно; описать его с помощью таблицы.
Задача 2. Доказать, что отображение множества {1, ,. ,
. . ., </}, заданное соотношениемs(i)=остаток (al, q)-\-\, в том
случае, когда а и q взаимно просты, есть подстановка 9-го порядка.
Указание. Пусть s(i)=s(j) и i>/. Тогда a(i—j) делится на q.
2. Циклическая структура. Рассмотрим какую-нибудь
подстановку s п-го порядка. Пусть некоторое целое число
а такое, что l^a^n, переводится подстановкой s в Ь.
Можно считать, что под действием подстановки s
элемент а занял место элемента Ь в множестве {1,2, ..., п).
Теперь посмотрим, куда попал элемент Ь. Пусть он занял
место элемента с, т. е. s(b)—c. Эти и следующие
аналогичные этапы изобразим так:
а~*-Ь-+с->. . . (2)
Подстановка действует на конечном множестве
{1, 2, . . ., п). Следовательно, в цепочке (2) встретится
число р, равное одному из предыдущих элементов
цепочки.
Теорема. Пусть р — первый элемент из цепочки
(2), для которого нашелся равный среди предыдущих.
Тогда р=а.
148
Доказательство. Пусть в р переходит г, т. е.
а~*Ь->-с—>-. . .—уг->р.
По условию число г не равно ни одному из
предыдущих элементов цепочки. Если рфа и, например, р—Ь,
то г переходит в Ь, т. e.s(r)—b. Но мы знаем, что а(а) = Ь.
Следовательно, а=г, что невозможно.
Получается, что под действием подстановки числа
а -» Ь
замещают друг друга как бы по кругу t \ или цикли-
r...-ь-с
чески.
Последовательность различных чисел а, Ъ, с, ..., г
такая, что s(a)-—b, s(b)—c,. . ., s(r)—a называется
циклом подстановки s.
Например, подстановка
1 2 3 4 5 6\ „.
,325614; W
имеет циклы 1, 3, 5; 2; 4, 6. Как видно из этого
примера, цикл может состоять и из одного элемента.
Наряду с выписанными циклами подстановки (3)
можно рассмотреть еще несколько циклов: 3, 5, 1;
5, 1, 3; 6, 4. Мы будем считать, что последовательности
а, Ь, с, . . ., г; Ь, с, . . ., г, а; с, . . ., г, а, Ь\. . .
определяют один и тот же цикл, поскольку они
определяют один и тот же способ замещения элементами друг
друга. Как правило, мы будем выписывать цикл,
начиная с наименьшего элемента. Цикл будет ограничиваться
скобками, запятые между элементами.цикла будут
опускаться. Итак, циклы подстановки (3) — (1 3 5) (2)
(4 6). Перечень всех циклов подстановки называется ее
разложением в циклы.
Задача 3. Построить разложение в циклы подстановок
а) /1 2 3 4 5N
U 4 2 3 1,
б) (\ 2 ... п'
2 ... п.
С
Различные циклы подстановки s не имеют общих
элементов. Если бы, например, имелись два цикла (a, b
с d) и (е А /) с общим элементом d, то из первого цикла
получаем a=s(d), из второго f=s(d), следовательно,
«=/. Так же получаем Ь—е, следовательно, s(e)—s(b)—d.
149
Элемент с не может присутствовать в первом цикле —
циклы должны быть равны.
Разложение в циклы однозначно определяет
подстановку. Рассмотрим, например, подстановку (3). Цикл
(13 5) дает три столбика записи подстановки в виде
таблицы
/135\
V351J'
цикл (2) дает один столбик
цикл (4 6) — еще два столбика
(11)-
Объединяем эти столбики в одну таблицу, упорядочив
по возрастанию элементы верхней строки, и получаем
исходную подстановку.
Задача 4. Определить подстановки по их разложениям в
циклы
а) (2 4 6) (1 3 5),
б) (1 2) (3 4).. (2ft+l 2k).
Подстановка, разложение которой состоит из одного
цикла, называется циклической. Например, подстановка
/1 2 3 4 5\
\2 3 4 5 i)
циклическая. Ее разложение в циклы есть (12 3 4 5).
Разложение подстановки в циклы широко
используется при построении алгоритмов, оперирующих с
подстановками.
3. Перемешивание элементов массива. Пусть дан
массив аи аг, ..., а„ и подстановка s порядка п. Пусть
требуется перемешать элементы данного массива в
соответствии с подстановкой s, т. е. получить массив,
элементы которого равны asa), asm,. . ., asin). Если нужно
присвоить значения элементам другого массива, скажем
массива Ьи Ь2,- ■ ., Ьп, т. е. положить bi=asll), Ьг—
=а8(2), . . ., bn=asm), то задача становится слишком
простой. Нашей задачей будет разработка алгоритма, в
результате применения которого перемешивание проис-
150
ходит на прежнем месте и дополнительный массив не
привлекается.
Разберем подзадачу. Зададимся некоторым целым ft
(l^ft^/z) и изменим нужным образом порядок тех ah
индексы которых принадлежат циклу подстановки s,
содержащему число ft.
Если s(k)=l, s(/)=m, . . ., s(v)=u, s(u)=k, то те
перемещения (присваивания), которые нужно
выполнить, можно схематически изобразить так:
«а*~ а* *-а,
I I
а„—...—а.
Эти перемещения будут произведены в результате
выполнения следующей серии приказов присваивания:
t: = ak; ah: = at; at: = am; ...; av: = aa; aa: = t.
Алгоритм будет иметь вид:
С\: t:=ak;
С2: x: = ft;
СЗ: пока s(k)^x выполнять начало ak: = as(k))
k: = s(k)
конец;
С4: ak: = t
Потребовались всего две дополнительные переменные.
Введением еще одной переменной можно добиться того,
чтобы функция s не вычислялась трижды для каждого ft.
CI: t: — ak:
С2: x: = k;
СЗ: y: = s(k);
С4: пока уфх выполнять начало ак: = ау;
ft: = у;
У- = s {у)
конец;
С5: ah: = t
Для полного решения задачи о перемешивании нужно
научиться находить ровно по одному элементу
(представителю) каждого цикла подстановки s. Для этого
из каждого цикла выбирается наименьшее входящее
в него число, и представители различных циклов
перечисляются по возрастанию. Первый представитель
это 1. Теперь выясним, не является ли 2 следующим
нужным нам представителем. Перебираем числа 2,
s(2), s(s(2)), . . . Если в некий момент среди этих чисел
151
встретится 1, то 2 входит в уже рассмотренный цикл,
переходим к числу 3. Иначе 2 объявляется
представителем очередного цикла. Так можно идти и дальше. Пусть
уже обследованы все циклы, наименьшие элементы
которых ^j—1, тогда проверяем, является ли i искомым
представителем. Эта проверка сводится к выяснению,
верно ли, что в последовательности s(i), s(s(i)), . . . нет
числа </. Можно выписать алгоритм решения
поставленной задачи:
Р: Дан массив ait ..., ап. Пользуясь
подстановкой s, как данной функцией, переставить
элементы данного массива в порядке asiv, as{2), ...
• • • > й$(я>>
PI: /: = 1;
P2: пока j^n выполнять
начало k: — s(j);
пока j < k выполнять k: — s(k)\
если k — j то применить С;
/: = / + l
конец
Алгоритм Р стал бы значительно более эффективным,
если бы удалось каким-то образом помечать элементы
массива, уже переставленные с помощью циклов.
В этом случае упростился бы поиск очередного
представителя цикла. Но если обзавестись массивом пометок,
то будет нанесен непоправимый ущерб самой идее —
обойтись без дополнительного массива. Здесь
возможны различные ухищрения. Например, если числа- аи
а2, ...,ап положительные, то можно их при
перемешивании временно заменять противоположными.
Пометкой будет, таким образом, знак минус.
Алгоритм Р находит себе важное применение в
следующей задаче. Пусть дана числовая матрица
'аХ\ «12 ... аы
«21 а23 . . . Clin | /дч
\aml атч • '• ■ атп/
Требуется найти транспонированную к ней матрицу
(5)
fl/u йп% • • • amn '
■■I'
152
а*1=ац. Иногда описания алгоритмов приходится
доставлять ge3 использования переменных с двумя
индексами, т. е. без матриц. Тогда поступают следующим
образом: матРиц.У (4) записывают в виде хъ х2,..., xN,
Motrin, гДе первые п чисел хи..., хп — это элементы
первой строки матрицы (4), следующие п чисел хп+и ...
Хт—элементы второй строки и т.д. Теперь можно
Сформулировать задачу по-другому: переставить числа хи
х2,..-, Хх так, чтобы после перестановки массив хи
х2',.--1 хх отвечал матрице (5).
Задача 5. Используя основные арифметические операции
и операцию остаток, описать алгоритм вычисления подстановки s,
определяющей переход от (4) к (5) для случая, когда матрицы (4)
и (5) записаны в виде xlt х.2, . . ., х,у, N=mn.
Задача 6. Пусть alt . . ., а7 — некоторые целые числа.
Пусть bi 67 —■ те же числа, взятые в каком-то другом порядке.
Доказать, что произведение (ях—bt)(a2—й2). . .(а7—Ь7)—четное
число.
Задача 7. Сколько раз вычисляется значение функции s
п /12 ... п— 1 л\-
в процессе применения алгоритма Р, если s—1 . I ?
Примечание. Пример, приведенный в задаче 7,
показывает, что в некоторых случаях алгоритм Р требует около па
вычислений функции s. Д. Кнут *) предложил усовершенствование
алгоритма Р, основанное на использовании вместе с подстановкой s
обратной к ней, т. е. такой подстановки t порядка га, что t(s(i))~
=s(t(i))—i для /=1, 2, . . ., п. Очевидно, что если подстановка s
имеет цикл ({г12 . . .ik-\i£), то подстановка t имеет цикл (tVu-i • • ■
.. .»а1\). Для выяснения, является ли число i наименьшим в
содержащем его цикле подстановки s, предлагается вместе с числами
s(i), s(s(i)), s(s(s(t'))), . . . одновременно рассматривать числа t(i),
t(t(i)), i(i(t(i))), ... до тех пор, пока в одной из этих
последовательностей не встретится число <f. Оказывается, что
усовершенствованный таким образом алгоритм Р потребует не более cnlog3ra
вычислений значений функций s и t (с — некоторая постоянная).
Но для применения этого алгоритма необходима подстановка t.
Задача 8. Полностью описать алгоритм Д, Кнута.
Задача 9. Сколько раз вычислятся значения функций
s и I в процессе применения алгоритма Д. Кнута, если
s=f 2 о ' ' ' ~_ ?)> а t— обратная к s? Как выглядит /?
4. Перестановки. Рассмотрим упорядоченный набор
чисел (ijtj .. ,in), отвечающий подстановке (1). Такие
наборы называются перестановками порядка п или
перестановками n-го порядка.
*) Д. Кнут — современный американский математик, автор
Многотомной монографии «Искусство программирования для ЭВМ».
153
В перестановке (t'ii2 .. .in) может найтись пара чисел
iu, iv такая, что u<Cv и i^>iv. В этом случае говорят, что
iu и iv образуют инверсию.
Можно сопоставить перестановке (i± it .. .in) общее
число инверсий в ней. В перестановке (4 3 2 1) имеется
6 инверсий: 4 стоит на 1-м месте, но больше чисел,
стоящих на 2-м, 3-м и 4-м местах,— это дает 3 инверсии;
3 стоит на 2-м месте, но больше чисел, стоящих на 3-м и
4-м местах,— это дает 2 инверсии; наконец, 2 стоит
на 3-м месте, но больше числа, стоящего на 4-м месте,—
это еще одна инверсия. В перестановке (12 4 3) —
одна инверсия. В перестановке (1 2 3 4) — 0 инверсий.
Задача 10. Доказать, что если в перестановке (iJ2. . Л„)
число инверсий больше нуля, то найдется k такое, что ih>ik+u
поменяв tfc и ift+1 местами, мы понижаем число инверсий ровно на 1,
Понятие числа инверсий в перестановке может быть перенесено
без изменений на произвольный числовой массив, в котором могут
быть и равные элементы. Утверждение, содержащееся в условии
задачи 10, сохраняет силу. Отсюда можно получить, что следующий
процесс преобразования числового массива всегда ■ завершается
после конечного числа этапов и приводит к упорядочиванию
элементов по неубыванию. Массив просматривается, начиная с первого
элемента, до тех пор, пока не встретится такая пара соседних
элементов, что второй элемент меньше первого. Если такой пары нет,
то все закончено, иначе элементы найденной пары меняются
местами, начинается новый просмотр и т. д.
Задача 11. Полностью описать предложенный алгоритм
упорядочивания.
Мы впервые в явном виде обсуждаем доказательство заверши-
мости выполнения алгоритма. Если алгоритм предполагает
поэтапную обработку объекта или массива объектов, то доказательство
завершимости сводится к доказательству конечности числа этапов.
Для проведения последнего доказательства достаточно сопоставить
объекту или массиву объектов его сложность — некоторое
неотрицательное целое число таким образом, чтобы каждый этап обработки
понижал ее. Как только после некоторого числа этапов сложность
объекта или массива объектов станет равной нулю, выполнение
алгоритма завершится. В приведенном примере сложностью было
число инверсий в массиве.
Если выполнение алгоритма действительно всегда завершается,
то такое сопоставление возможно — например, можно сопоставить
объекту или массиву объектов число этапов обработки. В случае,
когда заранее неизвестно, завершимо ли выполнение алгоритма,
это рассуждение ничего не дает нам для фактического определения
сложности (или доказательства невозможности этого определения).
Задача 12. Доказать, что выполнение алгоритма, состоящего
из одного шага:
пока п>1 выполнять
если четное(п) то п:—п12 иначе п:=п+1
завершается, каким бы ни было натуральное число п.
154
Указание. Определить сложность натурального п кяк
я+(_1)»+1.
Задача 13. Доказать, что выполнение алгоритма, состоящего
из одного шага:
пока п>\ выполнять
если четное (п) то л:=п/2+1 иначе я:=я+1
не завершается ни для какого натурального га>1.
До сих пор не доказана и не опровергнута завершимость для
любого натурального п выполнения алгоритма
пока я>1 выполнять
если четное(п) 'то п:=п/2 иначе п:=Зп-\-1
Будем называть перестановку четной, если в ней
четное число инверсий. Иначе будем называть ее
нечетной.
Понятие чётности перестановки кажется на первый
взгляд искусственным, однако оно отражает многое в
структуре перестановки. Сейчас будет
продемонстрировано применение понятия четности перестановки для
/
5
3
13
2
6
10
15
3
7
11
п
4
8
12
1
5
9
13
2
6
10
п
3
7
11
15
4
8
12
а) а)
Рис. 54.
доказательства неразрешимости задачи С. Лойда об
игре в «15». В этой задаче предлагается по правилам
игры в «15» перейти от позиции а) к позиции б), которые
изображены на рис. 54.
Вначале будет доказана следующая
Теорема. Пусть дана перестановка (it t*2 .. .г'„).
Пусть 1-^JK.l^.n. Тогда, если в данной перестановке
элемент ih переставить на место с номером I, оставив
относительный порядок всех других элементов прежним,
то четность перестановки изменится на
противоположную в том и только в том случае, если I—k — нечетное
число.
Доказательство. Пусть сначала l=k+l.
Тогда в перестановке меняются местами два соседних
элемента ih и t'ft+i. В результате этого число инверсий
155
увеличивается на 1, если it>ik, и уменьшается на 1,
если ii<.ih.
Пусть теперь /—&=г>1. Поменяем местами соседние
элементы г раз, продвигая ik в сторону it, при этом
каждый раз четность будет меняться на противоположную.
Отсюда следует утверждение теоремы.
Теперь об игре в «15». Любой позиции отвечает
некоторая перестановка чисел 1, 2, ..., 15 — для ее
получения записываем в строчку все числа первого ряда,
затем второго, третьего и четвертого. Пустую клетку
пропускаем. Рассмотрим, к каким преобразованиям
перестановки приводит передвижение шашки по
правилам игры. Перемещение вдоль горизонтального ряда не
приводит к изменению перестановки. Перемещение
вдоль вертикального ряда приводит к переносу числа на
новое место, причем разность номеров мест равна 4.
Это говорит о том, что допустимые ходы не меняют
четности имеющейся перестановки. Четность перестановки
инвариантна относительно допустимых ходов. Остается
заметить, что позиции а) отвечает нечетная переста*
новка (одна инверсия), а позиции б) четная (нуль
инверсий), следовательно, от позиции а) к позиции б)
перейти нельзя.
§ 2. Вычисление ап
1. Экономия умножений. Задача вычисления а" при
натуральном показателе кажется слишком простой.
Надо выполнить п—1 умножение:
ахахах ...ха (1)
Но число умножений можно существенно уменьшить.
Для n—2k имеем ап~ (aft)2, ясно, что в этом случае
потребуется не более k умножений. Пусть теперь n=2k+l.
Тогда a"=aikXa. Уже известен метод экономного
вычисления с2*; дополнительное умножение на а дает
требуемый результат. В обоих случаях экономится по меньшей
мере [л/2] умножений. Если быть последовательным в
применении этого метода, то экономия окажется еще
ощутимее, так как вычисление ак — это та же самая
задача.
156
Этот метод позволяет составить рекурсивный
алгоритм:'
А : Даны а и п, вычислить и — ап;
А\\ если п=\ то начало и: = а; выход конец;
А2: ft: = [л/2];
A3: 1: — остаток{п,2)\
Л4: и: = А(а, ft)2;
АЪ: если 1 = 1 то и: = иа.
Шаг Л4 содержит рекурсивное обращение.
Предстоит выяснить, какую экономию умножений
дает применение алгоритма А в сравнении с
тривиальным алгоритмом (1). Кроме того, хорошо бы
преобразовать полученный алгоритм в нерекурсивный.
Задача 1. Сколько умножений потребуется для вычисления
по алгоритму А значения ап, если /i=2m?
Задача 2. Сколько рекурсивных обращений, т. е.
упрятываний некоторых переменных с их значениями в магазин придется
выполнить при вычислении поалгоритму А значения а" дляге=2от?
2. Избавление от рекурсии. Алгоритм А применяется
так. Делится п на 2 с остатком: rc=2ft-H, /=0 или /=1.
Далее вычисляется ak и при этом k делится на 2 с
остатком. Это похоже на построение записи п в двоичной
системе: остаток дает очередную цифру, а частное
используется для построения старших цифр. Если запись
числа п в двоичной системе есть аяа/7_1.. .аь то алгоритм
А можно изобразить соотношением
aap«p-f-
a' = (aW-i'--aa)2.
Отсюда видно, что алгоритм А по сути дела
предписывает последовательное вычисление значений
а\ аарар-\ aVWV-t aW-i'""1. (2)
Переход к следующему значению от предыдущего—
это возведение в квадрат и, быть может, домножение на
а. Известно, что запись п в двоичной системе содержит
Hog2n]-r 1 цифр. Значит, применение алгоритма А
потребует llogjtt] возведений в квадрат и не более чем [log2rt]
домножении на а. Общее число умножений не превзойдет
2 llog2n]_<21og2n.
Точное число домножении на а на 1 меньше
количества единиц в записи числа п в двоичной системе.
157
Задача 3. Доказать, что алгоритм А требует заведомо
меньше 21og2n умножений.
При больших п разработанный способ дает в
сравнении с (1) существенную выгоду. Если «=50, то п—1«=
=49, а 2 [log2M]=10, на самом деле для получения а60
по" алгоритму А потребуется даже не 10, а 7 умножений:
запись числа 50 в двоичной системе есть 110010.
Построение массива цифр числа п в двоичной системе
идет, как обычно, от младшей цифры к старшей,
используются же цифры для вычисления а" в обратном порядке:
сначала старшие цифры, потом младшие.
По аналогии с (2) можно последовательно вычислять
aalt 0^t| t>) aVVi---a2a\ (3)
тогда цифры числа п будут использоваться, начиная с
младшей. Использованные цифры можно забывать.
Осталось выяснить, каким образом каждый последующий
член последовательности (3) вычисляется по
предыдущему. Здесь удобно рассмотреть последовательность пар:
аи а<2°>; а2, а^>; ...; ар, а^р~1\
а{%{) при г>0 получается возведением в квадрат а{2'~г\
Вычислив новую пару, старую можно забыть.
Параллельно вычислению пар будем строить произведение тех
(а2'), для которых ai+1^0. Получается нерекурсивный
алгоритм вычисления ап, которому не нужен
дополнительный массив:
В : Даны а и п. Вычислить и = а"\
В\: ы: = 1;
В2: q: = a;
ВЗ: Ь:=И
Б4: пока Ь выполнять
начало
1: = остаток (п, 2); п: = [п/2];
если 1=1 то u: = uq;
если и=0 то Ъ=Л иначе q: = q2
конец
Например, при вычислении а80 переменная q
принимает последовательно значения а, а2, а4, а8, а1в, а32,
переменная и — значения а, а2, а18, а50.
Задача 4. Сколько умножений потребуется для вычисления
а1000? Что будет быстрее вычислено в998, или о1"00?
Задача 5. Какое значение будет иметь переменная q после
вычисления а1000?
158
3. Расширение области применения алгоритма. Говоря
о способе вычисления а", мы полагали п натуральным,
но ничего не говорили о природе а — целое ли это число'
действительное или комплексное? Совершенно ясно, что
это неважно. Более того, неважно, является ли вообще
а числом. От а требуется принадлежность к
некоторому множеству, в котором определена операция
умножения, т. е. множеству, каждой паре элементов которого
сопоставлен третий элемент — произведение. От
умножения требуется только ассоциативность — без
ассоциативности непонятно, что такое а". Коммутативность
же, например, не требуется *).
Задача 6. В алгоритме В используется существование
левого единичного элемента в множестве с умножением, из которого
выбирается а (т. е. такого элемента 1, что \Xq=q для любого q
лз рассматриваемого множества). Правую часть приказа
присваивания и:=\ (шаг В\) нужно понимать именно в этом смысле.
Отказаться от этого предположения и переделать алгоритм.
Задача 7. Показать, что произведение двух действительных
чисел вида а+Ь V^2, где а и 6 — целые, есть число того же вида.
Содержится ли во множестве чисел такого вида единичный элемент?
Те же вопросы, если а — четное число. Вычислить (1— Y^f-
Рассмотрим матричное произведение. Матрицу,
которая содержит k строк и / столбцов, для краткости будем
называть k X /-матрицей.
Для k X /-матрицы
/аи ... au\
й = ( )
\аы ... аи/
и /хт-матрицы
определено их произведение аЬ, которое будет kx.m-
матрицей. Эта матрица (обозначим ее с) определяется
равенствами
сц=апЬц+апЬц-\-.. ЛанЬц,
1=1, 2,..., А,/=1, 2,..., т.
*) Умножение коммутативно, если ab=ba для любых
элементов а, Ь. Умножение ассоциативно, если для любых а, Ь, с имеет
место a{bc)= {ab)c.
159
Иначе говоря, элемент с индексами i, j матрицы
произведения равен сумме произведений соответствующих
элементов i-n строки матрицы а и /-го столбца
матрицы Ь.
Понятие матричного произведения очень важное, с
ним приходится сталкиваться во всех разделах
математики. Для нас будут особенно интересны два частных
случая. Первый — когда перемножаются две лX
«-матрицы (они называются также квадратными матрицами
и-го порядка). Результатом вновь будет «X «-матрица.
Второй — когда перемножаются /гX«-матрица и «XI-
матрица (ее называют вектор-столбцом «-го порядка).
В первом случае результатом будет квадратная матрица
пХп, например,
/1 2\ /5 6\_ /1X5 + 2X7 1х6 + 2х8\ /19 22 \ . .
\3 А) \7 8)~ \ЗХ5 + 4х7 3x6+4x8J V.43 50 J ' ^'
Во втором — результатом будет вектор-столбец «-го
порядка. Например,
f1 2\ /-5N /-1X5+2X6V / 7\
\за)\ е; V-3X5+4X6J {$)•
Умножение матриц «-го порядка при «>>1
некоммутативно. Можно указать случаи, когда аЬфЬа.
Задача 8. Вычислить
'5 6\ /1 2\
J 8)\За)
и сопоставить результат с (4).
Вместе с этим умножение матриц ассоциативно.
Задача 9. Доказать сделанное утверждение для квадратных
матриц 2-го порядка.
В множестве квадратных матриц «-го порядка
особую роль играет единичная матрица
.. 0\
.. О
40 0 ,., 1/
Умножение любой квадратной матрицы а на единичную
(справа или слева) не изменяет матрицы а.
Нетрудно видеть, что множество квадратных матриц
фиксированного порядка удовлетворяет всем условиям,
160
необходимым для применимости алгоритма В
вычисления а". Это можно, например, использовать для
вычисления элементов (с большими номерами)
последовательности, заданной рекуррентным соотношением
07i=SW„-i+ft'n-a (5)
и начальными значениями vu t>2.
Было показано, что непосредственное использование
соотношения (5) для организации рекурсии не
рационально. Более рациональным был признан способ
последовательного вычисления v3, vit..., vn с сохранением
на каждом этапе предпоследнего значения.
Рассмотрим формулу, которая выражает vn через п.
Это
V^C^l + C^, (6)
если уравнение %2—sk+t имеет простые корни Ях- и
а2, или
"» = (Ci + ctn)M, (7)
если уравнение №~sX+t имеет кратный корень %t.
Константы Ci и с2 отыскиваются по начальным значениям.
Вычисление vn сводится, если корни простые, к
вычислению п-х степеней двух чисел, двух умножений и
еще одного сложения. Быстро вычислять степени мы уже
умеем: на каждую уйдет не более 21og2n умножений.
В целом здесь потребуется не более 41ogan-r-2 умножений
и одно сложение. Если корень кратный, то вычисление
vn потребует не более 21ogaw+2 умножений и одного
сложения.
Этот способ в сравнении со способом
последовательного вычисления vs, vit..., vn обладает и рядом
недостатков. Прежде всего, он требует подготовительной работы,
довольно неприятной, хотя ее объем и не зависит от п.
Требуется найти корни характеристического уравнения
и составить, а затем решить систему линейных уравнений.
Значения могут получаться комплексными. Если корни
будут вычисляться приближенно, то погрешность будет
возрастать при возведении числа в n-ю степень, что при
больших значениях п приведет к серьезному искажению
результата. Оказывается, существует способ вычисления
vn> Для которого эти недостатки не имеют места и
который сохраняет логарифмический рост числа
выполняемых операций с ростом п.
С, А. Абрамов
161
Vn-l\
)■
Сначала докажем лемму.
Лемма. Пусть последовательность vu vt, v3,..,
является решением соотношения (5). Тогда для гС^Ъ
(vn \_fst
' Доказательство. По определению
произведения матрицы на вектор имеем
\lOJ\Vn-t) \Vn-i
Но svn-i+tvn-z—vn и, следовательно,
\*>п-\ J \Vn-iJ'
что и требовалось доказать.
Ключом для построения нового способа вычисления
vn будет следующая
Теорема. Пусть выполнено условие леммы. Тогда
Доказательство. Индукция по п:
Г если п=3, то см. лемму;
2° пусть утверждение верно для п—3, 4, ...,k.
Докажем, что оно верно для n=ft+l.
По лемме
(vk+i\_(s t\(vk \
По предположению индукции
(S.,)-(;'.)-(»•■
Следовательно,
(ГК'.НО'.га-О'.Гв)-
Теорема доказана.
Получается, что vn можно находить следующим
способом: вычислить матрицу (.*) , умножить на нее
вектор ( ,а ] и взять первую компоненту этого вектора.
162
Если все исходные данные целочисленны, то
проделываемые операции не выведут из множества целых
чисел.
Если следовать предлагаемому способу и экономно
возводить матрицу в n-ю степень, то потребуется не более
21og2(n—2) матричных умножений. Вычисление
элемента произведения двух матриц второго порядка потребует
не более двух умножений и одного сложения. Значит,
умножение двух матриц второго порядка требует не
более 8 умножений и 4 сложений. Итак, требуется не
более 161og2(n—2) умножений и 8 log2(n—2) сложений.
Далее нужно будет умнож! ть матрицу на вектор. На
это уйдет не более 4 умножений и 2 сложений. Таким
образом, предложенный способ вычисления vn требует
не более 161og2(«—2)+4 умножений чисел и не более
Slog2 (n—2)+2 сложений чисел.
Если бы vn вычислялось так, как мы делали это
раньше, то было бы затрачено 2(п—2) умножения и п—2
сложения чисел. Мы видим, что при вычислении новым
способом уже при п=66 имеется выигрыш в числе
операций в сравнении с прежним способом. При увеличении
п этот выигрыш будет возрастать. Если п=1000, то
161og2(rc—2)+4<16-10+4= 164, в то же время 2(п—2)=
= 1996. Еще нужно учесть, что 16 log2(ra—2) — это
оценка сверху числа умножений в новом способе, а 2 (п—2)—
точное число умножений в прежнем способе. Если п=
= 1000, то точное число умножений в новом способе
8-15+4=124, так как запись в двоичной системе 1000
есть 1111100110, и число матричных умножений, которое
необходимо для вычисления 998 степени, равно 15.
Задача 10. Написать матрицу для вычисления чисел
Фибоначчи разработанным способом.
Задача 11. Обобщить разработанный способ на соотношения
k-vo порядка
u„ = aiu„_i+, ,. + aft«n_ft,
«!, «2> . . ., Uk — данные числа. Как выглядит матрица, на которую
нужно умножить вектор
/""-г\
6*
163
чтобы получить вектор
(п)
Какова оценка числа умножений и сложений? Что
представляет собой обобщение в случае fe=l?
Задача 12. Вычислить каким-нибудь способом наименьшее
значение п, при котором 161og2(n—2)+4<2(«—2) (это значение
меньше, чем 66).
* # *
При вычислении а" с помощью алгоритмов А, В,
помимо тех умножений, количество которых было
оценено, приходится строить цифры числа п в двоичной
системе. Это требует еще некоторого количества
арифметических действий (кроме, конечно, того случая, когда п
задано в двоичной системе). Не следует думать, что
другие алгоритмы не требуют никаких дополнительных
действий. Например, тривиальный алгоритм (1)
предполагает что-то вроде вычитаний из я по 1 до тех пор, пока
не получится О.
Число п в двоичной системе имеет llQg2«]+l цифр.
Ровно столько требуется произвести делений g остатком
на 2, если применяются алгоритмы А или В.
Если а — это не число, а, например, квадратная
матрица порядка k, где k — большое число, то объем работы
по построению цифр числа п ничтожен в сравнении с
работой по умножению матриц.
§ 3. Алгоритмы с логарифмической трудоемкостью
1. Поэтапное упрощение задачи. Для двух разных
задач — поиска в упорядоченном массиве из п элементов
и вычисления а" — удалось найти алгоритмы решения,
которые требуют не более logara действий вместо п или
п — 1 действий, требуемых тривиальными алгоритмами.
В обоих случаях целое число п характеризует сложность
задачи. Оба алгоритма имеют сходные черты: с помощью
каждого из них задача решается в несколько
однотипных этапов; количество действий, которое приходится
производить на каждом этапе,— величина, ограниченная
некоторой константой с, не зависящей от номера этапа;
164
при переходе к новому этапу сложность задачи
уменьшается примерно вдвое.
Слово «примерно» добавляется из-за того, что сложность п
может быть нечетной. Тогда на следующем этапе сложность будет
равна [л/2] или [(я+1)/2].
Эта неопределенность вносит затруднения в работу
по нахождению возможно более точной, зависящей от п
границы для общего числа действий. Укажем метод
анализа алгоритмов, исключающий эту неопределенность.
Этот метод является достаточно универсальным и может
быть применен не только в тех задачах, где сложность п
при переходе к новому этапу преобразуется в [п/2] или
[(и+1)/2]. Он основан на выборе бесконечной
возрастающей числовой последовательности Si, s2,...,
которая обладает следующими свойствами:
Г известно, как решать задачу для n^Si",
2° если n^Sfe при k^2, то известно, как перейти к
задаче со сложностью n'^sft_f.
Если последовательность s подобрана и переход к s
с меньшим индексом требует не более с действий, то при
условии sft_1<n^sft (/£5s2), общее число действий не
превзойдет
c(k—1)+число действий, необходимых при tt^Si (1)
Наличие последовательности s с быстрым ростом
говорит о хорошем качестве алгоритма.
Для задач поиска в упорядоченном массиве и задач
вычисления а" существуют тривиальные алгоритмы.
В первом случае это — сравнить значение с ап и, если
не совпало, перейти к поиску в а*,..., а„-ь а во втором
случае — вычислить ап~х и домножить на а.
Последовательность s для них представляет собой 1, 2, 3, 4, ... .
Выше были приведены более рациональные
алгоритмы решения этих задач. Для них эта
последовательность есть 1, 2, 4, 8, ... Докажем это. Для этого
выберем число k такое, что п<12А; если п четно, то
п/2^2*-1, если п нечетно, то «+1^2* и,
следовательно, (я+1)/2 (целое число!) не превосходит 2k~l.
Таким образом, [п/2]<2*-* и [(п+1)/2]<2*"1.
Пусть Sj=2', i=0, 1, 2,...; тогда число этапов,
необходимых для перехода от задачи со сложностью п
к задаче со сложностью <Л, не превосходит [log2 n]+l.
При поиске делением пополам каждый переход к
задаче с меньшей сложностью требует выполнения одного
165
сравнения; если n^l, то сравнений не нужно. Получаем
в соответствии с (1) оценку [log2«]+l.
При вычислении ап по алгоритму из предыдущего
параграфа каждый переход к задаче с меньшей
сложностью требует не более двух умножений. Если л^1,
то умножений не нужно. Получаем в соответствии с (1)
оценку 2[log2n]+2.
Задача 1. Выведенная оценка несколько грубее прежней
2[log2"]- Уточнить рассуждение предыдущего абзаца и избавиться
от слагаемого 2.
Указание. Взять в качестве последовательности s не 1, 2.
4, . . ., а 4, 8, 16, ...
Присутствие двоичного логарифма в оценке для
числа действий характерно для таких алгоритмов, которые
каждым своим этапом примерно вдвое уменьшают
сложность задачи. Последовательность s в таких случаях
состоит из степеней двойки. Алгоритмам иной
структуры могут отвечать другие последовательности..
Задача 2. Имеются п монет, из которых одна фальшивая
(более легкая). Имеются чашечные весы без гирь. Требуется
определить фальшивую монету. Найти такой метод решения этой задачи,
которому отвечает последовательность 1, 3, 9, 27, ... Вывести
оценку для числа взвешиваний. Сколько взвешиваний потребуется
для 1000 монет?
2. Усложнение анализа. Выражение (1) неприменимо,
если не существует оговоренной константы с.
Если алгоритм таков, что при переходе от задачи со
сложностью n^Sfe к задаче со сложностью ra'^sft_i
требуется не более ch действий и ci — граница количества
действий, требуемых для решения задачи со сложностью
^Si, то в качестве оценки числа действий, требуемых
при решении задачи со сложностью п, где sm-i<.tv£^.sm,
можно взять
т
2 с,. (2)
/= 1
Таким способом можно оценить число действий в
задаче отыскания остатка от деления целых чисел а п b
с помощью операций вычитания и сравнения. Во второй
главе был выбран простейший алгоритм: многократно
зычитать из числа а число b до тех пор, пока это не
приведет к отрицательному значению разности. Такой
алгоритм требует [alb] вычитаний и столько же сравнений.
166
рассмотрим другой алгоритм, близкий по идее делению
«столбиком». Предположим, что мы имеем записи чисел
а и Ь в личной системе. Тогда количество цифр в
частном, записанном в <7-ичной системе, определяется как
наименьшее целое т такое, что qmb>a. Если т=0, то
й — это и есть остаток. Старшая цифра и — это целая
часть от деления а на qm~lb. Искомый остаток равен
остатку от деления а—vqm~lb на Ь. Видно, что удобно
работать с двоичной системой. Старшая цифра —
наверняка единица, и нужно только определить, в каком
разряде она находится. Все это показывает, что можно
действовать так: перебираем числа b, 2b, 4Ь,
(переход от предыдущего к следующему производится одним
сложением) до наибольшего, не превосходящего а. Затем
вычитаем найденное значение из а и возобновляем все
сначала.
R : Нахождение остатка от деления а на b с
помощью операций +, —, >. Значение остатка
присваивается а;
R\: пока а>Ь выполнять
начало с: — Ь;
пока а > с повторять
начало d:—c; c: = c-\-c конец)
a: = a—d
конец
Сложность здесь естественно определять величиной а,
взяв в качестве последовательности s числа b, 2b, Ab,...,
т. е. sh—2k~1b, k=l, 2,... Чтобы найти такое число nf
что 2n~1b<la^L2"b, и перейти к новому а, меньшему
2п~1Ь, требуется п операций сложения и одно
вычитание— всего п+1 операция. Если а<.Ь, то сложений и
вычитаний производить не придется. В соответствии с (2)
получаем оценку числа сложений и вычитаний:
п
2 (*' + 1), где n = [\og,(a/b)l
i = i
Полученная величина равна
(п + 3) л/2 = ([log, {a/b)] + 3) [log, (a/b)]/2.
Известно, что при лг~->-оо величина (logs*)2 растет много
медленнее, чем х. Это приводит нас к заключению, что
алгоритм R существенно лучше прежнего алгоритма для
больших п.
167
Задача 3. Описать алгоритм нахождения частного и остатк
от деления а на Ь, основанный на идее алгоритма R. Проанализи9
ровать этот алгоритм.
Задача 4. Если запомнить последовательность Ь, 2Ь,
или воспользоваться операцией деления на 2, то остаток можно
найти примерно за 41og2(a/6) операций. Построить этот алгорцТч
3. Теорема Ламе. Рассмотрим другой прием оценки
числа действий, основанный на сравнении сложности
задачи на различных этапах с элементами
последовательности. Пусть имеется неограниченно возрастающая
последовательность чисел tu t2. Т. такая, что на послед.
нем этапе применения алгоритма обязательно получается
сложность ~^U, на предпоследнем этапе ^/2 и т. д.
Пусть сложность рассматриваемой задачи есть п, а
число необходимых этапов т. Тогда по условию ri^tm,
Если найдено к такое, что n<.tk+i, то, поскольку
последовательность t возрастающая, т^к. Таким образом,
наличие последовательности t дает способ оценки числа
этапов.
Задача 5. Получить этим методом оценку числа сравнений,
требуемых алгоритмом деления пополам. На последнем этапе
применения этого алгоритма рассматривается массив, состоящий из
двух элементов, на предпоследнем — состоящий по крайней мере
из трех элементов и т. д.
Указание. Последовательность tlt tit t3, ... может быть
образована так: ty=2, tn=2tn-1—1.
Оказывается» для алгоритма Евклида нахождения
наибольшего общего делителя двух натуральных чисел
flo, cti(a£>ai) можно подобрать такого рода
последовательность и оценить предложенным способом число
делений с остатком. Сложностью будет меньшее число сц,
а последовательностью — числа Фибоначчи, начиная со
второго:
Пусть применение алгоритма Евклида к числам а0, щ
дает последовательность ненулевых остатков аг, а3, ...
• • •> О-т'
а£ = д2а2 + а3,
««-i^i-A-i + a»-!, (5)
Лт-1-Ятат-
168
Нужно доказать, что
или, короче,
ат-8>"«+1, s=0, 1,..., m—1.
Проведем индукцию по s.
Г Пусть s=0. Очевидно, что ат^и8=1. Пусть s=l,
Покажем здесь, что ат-^и»=2. Если бы выполнялось
дт_1=1, то предпоследнее деление в (5) выполнилось
бы без остатка. ,
2° Пусть утверждение справедливо для s=0, 1,..., k,
и, в частности, am_fe>Mft+s, am-k+i^uk+i. Тогда имеем
Все доказано.
Задача 6. Почему в п. 1 доказательства непременно нужно
проверять истинность утверждения и для s=0, и для s= 1?
Теперь ясно, что должно выполняться а{^ ит+1,
т. е.
■.>7*((W-№T).
того, что
<l и I71V-2-J <i.
откуда, ввиду того, что
!— У~Ь
2
получается
а
.>й№Г-'-.
оценк
m+l<
Это дает оценку числа этапов:
g(l+ai) + lg_^"5 _;
% 2
= logi±r! Ю lg (1+ а,) + logi±r3 Vb =
= 4,784971... lg(l+at) +1,672275... <
<51g(l+ai) + l,7
(lg—логарифм по основанию 10).
Попытаемся заменить десятичный логарифм
количеством цифр числа at в десятичной системе. Если
169
это количество есть п, то 10"~1^а1 < 10" и ах+ 1^10",
Следовательно, lg^+ajO и m-f-1 < 5л + 1,7,
Поскольку т и Ъп — числа целые, то т+1^5/г+1
и т^.Ъп. Нами доказана
Теорема Ламе *). Число делений с остатком в
процессе применения алгоритма Евклида не превосходит
упятеренного количества цифр меньшего числа аи
записанного в десятичной системе.
Задача 7. Доказать, что оценка, полученная в теореме Ламе,
неулучшаема в том смысле, что, вообще говоря, неверно
утверждение «m<5n».
Указание. Из рассмотрения доказательства утверждения
am-s^us+2 убедиться, что медленнее всего алгоритм Евклида
применяется к соседним числам Фибоначчи (все частные, кроме
последнего, равны единице). Для построения опровергающего
примера подобрать пару соседних чисел Фибоначчи.
Применяя логарифмирование по другому целому
основанию, большему 1, можно из (6) получить аналог
теоремы Ламе для любой системы записи чисел. Если
обозначить nq (ai) количество цифр числа аи записанного
в </-ичной системе, то нетрудно вывести оценку
• m<([log1+K-5(7l + 1)ng(fli)-
2
Для двоичной системы получаем, что т^2п2{а1), так как
log,+у-ъ2=\,440420... Эту оценку мы уже получали
2
ранее.
Задача 8. Найти число v такое, что для всех целых a^v
выполнено 5 ([lg a1]+l)<2([log2a1]+ ).
Задача 9. Как выглядит оценка числа" шагов в четверичной
системе?
Появление логарифма в верхней границе для числа
операций связано с тем, что последовательность, с
которой сравниваются сложности поэтапно возникающих
задач, имеет степенной рост. (Для чисел Фибоначчи
выполнено приближенное равенство ип ^"J7rl—2—/• J
4. Алгоритмы, близкие двоичным. Рассмотрим два алгоритма
обработки массивов, построенные на идее, близкой идее деления
пополам. Операция разбиения массива на две примерно равные
*) Ламе (Г. Ламме), (1795—1870) — французский математик
и инженер, в 1820—1832 гг. работал в России.
170
части — начало и хвост, здесь заменяется на следующую.
Переставим элементы at ап так, чтобы сначала шли элементы
меньшие первого, затем — первый элемент, затем—большие
элементы. Это преобразование может быть выполнено поочередным
сравнением первого элемента со всеми остальными.
Дополнительный массив для этого не требуется—достаточно двух
переменных р и q, показывающих, сколько элементов в начальной
и конечной частях уже занято. Элемент, бывший первоначально
первым, расположен на (p-f-l)-M месте и сравнивается со
следующим за ним.
D: Дан массив at an. Переставить его элементы так,
как объяснено в тексте;
DU р:=0;
D1: q:=0;
Ш: пока p + q < л—1 выполнять
если ар+1 >ар+2 то начало
и:=ар+\\ ар+1: =ар+%;
ар + 2:=и; р;=р + \
конец
иначе начало
tr.=an-g\ a„-9:=ap+i;
ар+2:=и; q:=q+\
конец
Первый алгоритм, опирающийся на алгоритм D—алгоритм
упорядочивания в порядке возрастания элементов aj, ..., ап
на том же месте. Ясно, что в результате алгоритма D первый
элемент становится на нужное место. Теперь рекурсивно
применим описываемый алгоритм упорядочивания к каждой из двух
частей — начальной и конечной (если число элементов части
на меньше единицы).
Второй алгоритм предназначен для поиска 6-го минимума
в данном массиве (наименьший элемент — это 1-й минимум,
следующий по величине — 2-й и т. д.). Пусть после применения
алгоритма D к массиву alt .,., ап значение р+1 оказалось
больше k. Это означает, что задача свелась к поиску k-ro
минимума в начальной части (число элементов, среди которых ведется
поиск, уменьшилось). Если p-\-l—k, то поиск закончен.
Наконец, если р+1 < k, то нужно найти (k—р—1)-й минимум в
конечной части ар+2< •■■< ап\ уменьшился и диапазон поиска,
и номер минимума.
Задача 10. Обобщить алгоритм D так, чтобы его можно
было применять не только ко всему массиву ai, .... a„, но и
к его части as, ai+1, ..., af, s и t —данные числа.
Задача 11. Откажемся от предположения о том, что а{, ...,а„
попарно различны. Внести уточнения в алгоритм D и алгоритм
поиска fe-ro минимума.
Хотя словесное описание алгоритма поиска /г-го минимума
рекурсивно, несложно дать нерекурсивное описание.
Задача 12. Дать точное циклическое описание этого
алгоритма.
В алгоритме упорядочивания избавиться от рекурсии трудно.
Алгоритм поиска fe-ro минимума особенно интересен при
fc = [n/2]-|-l: в этом случае в результате получается так
171
называемая медиана массива. Необходимость вычисления медиан
больших массивов возникает во многих социологических и эко-
номических исследованиях.
Анализ количества сравнений, требуемых двумя
предложенными алгоритмами, достаточно сложен. В двоичных алгоритмах
трудности возникали уже из-за того, что разбиение массива
давало две части, число элементов в которых могло разниться
на единицу. Здесь трудности значительно серьезнее.
Впрочем, нетрудно видеть, что в худших случаях эти
алгоритмы близки по числу сравнений к тривиальным алгоритмам.
Вместе с этим, среднее число сравнений, требуемых этими
алгоритмами, невелико. Предположим, что все значения at, ..., ап
различны и все п\ перестановок этих величин в одинаковой
степени возможны. Тогда для определения среднего числа
Сравнений, требуемых некоторым алгоритмом, достаточно вычислить
u„i — число перестановок, для каждой из которых требуется
одно сравнение, vn2 — число перестановок, для каждой из
которых требуется два сравнения и т. д. Искомое среднее будет
равно (vni + 2vni + 3vn3+...)/п\.
Оказывается, что среднее число сравнений, требуемое
предложенным алгоритмом упорядочивания, есть c„nlogn, где с„
при я=1, 2, ... образуют ограниченную последовательность.
Среднее число сравнений, требуемое для вычисления медианы
массива а±, ..., ап, есть спп и при больших л выполнено
приближенное равенство сп « 2 (1+1п 2).
* * *
Анализ некоторых алгоритмов может потребовать
привлечения последовательностей совсем другого вида.
В таких случаях верхняя граница описывается не через
логарифм, а как-то иначе.
Дополнение I. ПЕРЕХОДЫ
Иногда при записи алгоритмов считают удобным
применение приказов перехода, например,
перейти к А2; перейти к СЮ.
Приказ перехода вызывает прерывание выполнения
естественной последовательности шагов, и заставляет
продолжить выполнение алгоритма с шага, указанного
после перейти к.
1. Исключение составных приказов. Составной
приказ в алгоритме #(гл. I, § 3) входил в условный
приказ шага #1.2:
#1.2: если <Л, Е, В> то начало С: — Е\ выход конец
Приказы перехода позволяют избавиться от
составных приказов. Для этого шаг #1.2 можно
заменить тремя шагами:
#1.2.1: если ~|<Л, Е, By то перейти к #2.1;
#1.2.2: С:=Е;
#1.2.3: выход
Видно, что шаги #1,2.2 и #1.2.3 выполняются
только тогда, когда выполнено условие <Л, Е, By.
Если <Л, Е, By не выполнено, то после #1.2.1 сразу
начнет выполняться шаг #2.1.
В общем случае, когда в алгоритме X
встречается шаг
ХМ: если В то начало Pf; Р2; ... ; Рк конец (1)
его можно заменить последовательностью шагов
ХАМ: если ~\В то перейти к XN'\
XN.2: Р{,
XN. fe + 1: Pk\
Обозначение XN' использовано для шага, который
173
следовал в алгоритме X вслед за шагом XN.
Обозначение XN + 1 не использовано, поскольку возможно,
что jV—это не число, а последовательность чисел,
разделенных точками.
В том случае, когда встречается составной приказ
XN: если В то начало Р^ ... ; Рь конец
иначе начало Qt\ ... ; Qm конец;
(2)
можно поступить так:
XNA: если ~\В то перейти к XN. fe + 3;
XN.2: , Р±;
XN.k+l:
XN.k + 2:
XN.k + 3:
XN.k + i:
*V.
перейти к XN'
Qii
Q2;
XN.k + m + 2: Qm;
He будь шага
XN. k + 2: перейти к XN'\_
в том случае, когда истинно В, один за другим выполнились
бы все приказы Pf, .... Рп, Qi, ..., Qm.
Задача 1. Как свести выполнение шага (2) к выполнению
шагов, не содержащих составные приказы, если по какой-то
причине нежелательно заменять проверку условия В на проверку
условия ~\В7 После того как будет найдено решение, переписать
его для шага (1).
Задача 2. В заменах составных приказов, которые
предлагались, использовалось предположение, что вслед за шагом
XN идет еще по крайней мере один шаг XN'> Как быть, если
шаг XN был последним?
Ответ: вместо переход к XN'- поставить выход,
2. Вычисление суммы слагаемых без использования
приказа цикла. Алгоритм Н (гл. II, § 3) решает
задачу вычисления суммы 1 + 1/2+ ... + 1/п для любого
натурального n^sl. Приказ перехода позволяет
записать его без приказа цикла:
Н : Дано п. Вычислить 1 + 1/2+ ... + 1/л;
HI: s:=0;
7/2: i: = 0;
#3: i: =i + l;
НА: s: =s+l/i;
НЪ: если 1фт то перейти к НЗ
На этом частном примере продемонстрирован
общий прием исключения из алгоритма приказа повто-
174.
рять ... пока не ... В общем случае, если алгоритм
X содержит шаг
XN: повторять Р пока не В
то его можно заменить последовательностью шагов
XN.l: P;
XN.2: если ~]В то перейти к XN.l
Если приказ Р составной или приказ цикла, то
можно шаг ХЛМ подвергнуть дальнейшей детализации.
Легко преобразовать и приказ
пока В выполнять Р
Пусть этот приказ составляет содержание шага XN,
тогда
XN: если В то начало Р; перейти к XN конец
или
ХЛМ: если ~]В то перейти к XN'\
XN.2: Р;
XN.3: перейти к XNA
Снова использовано обозначение XN' для шага,
который следовал в алгоритме X вслед за XN. Сделаем
оговорку: если XN был последним шагом, то вместо
перейти к XN' нужно поставить выход.
Задача 3. Без применения приказа цикла составить
алгоритм вычисления суммы положительных и числа отрицательных
элементов массива аъ а%, ..., аюоо- Пользоваться можно
операцией сложения чисел и операцией отношения <.
3. Один из способов исключить ссылки на другие
алгоритмы. Пусть имеется набор операций над
словами, содержащий операцию и. Если F—алгоритм Н,
применимый к любому слову х, такой, что F (х)—
то же слово, то алгоритм G построения слова
"(F (x), F (^(х, «а»))) будет иметь вид:
G: по данному слову х вычислить y = ^(.F{x),
F («(*, «a»))),
Gl: y:="(F(x), F("(x, «а»))).
Такой алгоритм содержит два обращения к уже
составленному алгоритму F. Это избавляет от
необходимости повторять в алгоритме несколько раз один
и тот же кусок.
Возможность включения в алгоритм приказов
перехода позволяет и без обращения к другим алгоритмам
избегать повторений. Пусть, для определенности,
алгоритм F состоит из 130 шагов: F'l, F2, ..., F130.
Обозначим результат выполнения алгоритма F через v.
175
Вот как можно составить алгоритм G с приказами
перехода:
Gl:p: = l;
G2: перейти к G9;,
G3: у: =у;
G4: х: = w{x, «a»);
G5: р:=2;
G6: перейти к G9;
G7: у:=»(у, v)\
G8: выход;
G9: ...
G138: ...
G139: если />= 1 то перейти к G3;
G140: перейти к G7
В шагах G9—G138 должно быть записано то, что
было записано в шагах Fl—F130 алгоритма F.
Предполагается, что алгоритм F не изменяет значение
переменной х.
Задача 4. Алгоритм F может содержать приказ выход. Чем
должен быть заменен этот приказ в процессе преобразования
шагов F1— F13Q в шаги G9—G138?
Ответ. Приказом перейти к G139
* * #
Мы видели, что приказы перехода обладают
большой универсальностью: с их помощью можно
исключить составные приказы, приказы цикла и обращения
к другим алгоритмам.
Интересно, что если рассмотреть приказ
если В то перейти к XN (3)
где В—логическое выражение, a XN—обозначение
некоторого шага алгоритма, не как условный приказ
с приказом перехода после то, а как единый приказ
(назовем его приказом условного перехода), то
можно исключить из алгоритмов условные приказы.
Например, шаг, содержащий условный приказ*
ХМ: если В то Р иначе Q
заменяется на
ХМЛ: если В перейти к ХМ Л;
ХМ.2: Q;
ХМ.З: если И то перейти к ХМ'',
ХМЛ: Р
176
Следует обратить внимание на шаг ХМ 3- если
позволено употреблять приказы условного перехода
то простые приказы перехода, строго говоря, не
нужны, так как приказ
перейти к XN
всегда можно заменить на приказ
если И то перейти к XN
Получается, что все алгоритмы, которые мы
составляли ранее, можно записать, пользуясь только
приказами присваивания, выхода и условного
перехода (3). Можно было с самого начала строить все
■
Ч • = остаток(п,т)
Ответ: л I
Рис. 55.
Ответ: s,m А:~/<+1
s: = s+at
т:=т+1
Рис. 56.
алгоритмы, используя только эти приказы. В этом
случае первоначальный набросок алгоритма удобно
представить в виде блок-схемы. Принцип составления
блок-схем нетрудно усвоить, рассмотрев примеры.
На рис. 55 представлена блок-схема алгоритма
Евклида нахождения наибольшего общего делителя двух
натуральных чисел п, т (п^т). Блок-схема
алгоритма решения задачи «для данного массива аь а2, ..., аа
найти s—сумму положительных и т—число
отрицательных элементов» дана на рис. 56. В блок-схеме
177
фиксируются основные этапы построения объектов и
отмечаются переходы. В овальную рамку заключаются
условия, в прямоугольную—действия.
Задача 5. По блок-схеме, приведенной на рис. 56,
составить алгоритм, используя только приказы присваивания, выхода
и условного перехода.
Задача 6. Составить блок-схемы алгоритмов X и Y\
Х\: Р;
Х2: повторять Q пока не В;
ХЗ: R;
YU Р;
Y2: пока В выполнять Q;
УЗ: R
где В— логическое выражение, Р, Q, R — некоторые приказы.
Замечание. Блок-схемы должны отражать те варианты
алгоритмов, в которых используются приказыР, Q, R и переходы,
таким образом, Р, Q, R нужно заключать в прямоугольную рамку,
а В — в овальную.
Нетрудно заметить, что алгоритмы, включающие
условные приказы, составные приказы, циклы и
обращения к другим алгоритмам, выгодно отличаются
от алгоритмов, построенных исключительно на
условных переходах. Условные и составные приказы, циклы,
обращения к алгоритмам—это такие средства
описания, которые в значительной мере обеспечивают ясность
структуры алгоритма, а это часто позволяет
сравнительно легко проводить анализ и проверять
правильность алгоритма, изменять алгоритм в соответствии
с изменением условия задачи, заимствовать элементы
одного алгоритма при конструировании другого.
Дополнение II. ОБ ОДНОМ ПОЛЕЗНОМ
КАЧЕСТВЕ РЕКУРСИИ
Если способ построения объекта описан
рекурсивно, то многие свойства этого объекта сравнительно
легко могут быть доказаны методом математической
индукции. Рекурсией устанавливается связь между
объектами разной сложности—это как раз то, что
нужно для индуктивного перехода.
Взаимоотношение рекурсии с индукцией
обнаруживается и следующим наблюдением: обращение из
одного алгоритма к другому аналогично ссылке на
178
лемму в доказательстве теоремы; рекурсивный алго
ритм содержит обращение к себе—здесь прямая
аналогия с доказательством теоремы по индукции.
1. Центр тяжести многоугольника. Пусть п-уголь-
ник Р задан своими вершинами ри р2, .,., рп.
Определение точки, называемой центром тяжести Р,
можно дать через алгоритм ее построения:
Iе центр тяжести двуугольника (отрезка) ргр2 есть
середина отрезка р1р2;
2° центр тяжести n-угольника /^Ра •••/>/. строится
так: центр тяжести (п—1)-угольника/?±ра.. ./>„_!
соединяется отрезком с вершиной рп. Искомый центр
тяжести—точка проведенного отрезка, делящая его в
отношении (п—1).*1, считая от вершины рп.
Предложенное может быть без труда переписано в
привычной форме алгоритма построения с помощью
циркуля и линейки. Однако и без этого ясно видна
рекурсия — переход от вершин plt р2, ..., рп к
вершинам plt p2, ..., рп--у. Двуугольник считается
простейшим случаем.
Введенное понятие центра тяжести многоугольника
согласуется с физическим понятием центра тяжести
системы материальных точек. С другой стороны,
рассматривая это определение, можно подумать, что центр
тяжести зависит от порядка перечисления вершин.
Однако это не так.
Имеет место следующая
Теорема. Центр тяжести многоугольника рь
р2 ... рп, понимаемый в соответствии с данным выше
определением — алгоритмом, не зависит от выбранного
порядка вершин.
Доказательство. Зафиксируем некоторую
точку а в плоскости данного многоугольника и сопоставим
каждой точке р этой плоскости вектор р = ар. В
частности, точкам pit p2, ... рп сопоставим векторы
р± — арх, р2=ар2, ... рп = арп. Покажем, что вектор,
сопоставленный центру тяжести, есть функция
векторов pit р2, ..., р„, не зависящая от порядка
аргументов. Более точно, этот вектор равен
7r(Pi + P8+... + pJ-
179
Применим индукцию по п:
Iя для я = 2 справедливость утверждения следует
'.з правила параллелограмма и свойства диагоналей
араллелограмма делиться в точке пересечения попо-
ам (рис. 57);
2° пусть все верно для п = 2,3, ...,k. Пусть v —
ектор, сопоставленный центру тяжести многоуголь-
1ика с вершинами plt р2, ..., рк. Очевидно, что центру
тяжести многоугольника с вершинами pt, р , pft+1
будет сопоставлен вектор (рис. 58)
w = v + ~-(pft+i—v).
По предположению индукции,
V = jlPl+'-. + Pft).
Поэтому
« = v + F|T(pft+j-v) = FArv + FpT-pft+,-
= k+T ^ + • •' +р^ +fe+T p*+1e
= £qrr (Pi + Р» + ' *' + pft+^'
что и требовалось доказать.
Задача 1. Доказать, что если многоугольник Рь р%, •••
,,,, р„—выпуклый, то он содержит свой центр тяжести.
(Плоская фигура называется выпуклой, если вместе с двумя любыми
своими точками R и S она содержит весь отрезок RS.)
180
2. Наибольший общий делитель двух чисел Фибо
наччи. Рекурсивное (рекуррентное) определение чисел
Фибоначчи
хорошо тем, что позволяет доказывать методом
индукции многие свойства этих чисел. Эти доказательства
крайне усложнились бы, если воспользоваться в
качестве определения формулой
„ - х (1+VJLY l (1-Уъ У
и"-ут\ 2 ; —yj{ 2—) •
Будем полагать, что и0 = 0.
Задача 2. Убедиться, что соотношением
"л = «П-1 + "л-2
при начальных условиях и0 = 0> «i=l определяются те же
«1, "а. "з. "■• что и при начальных условиях «1п=и2=1.
Теорема. Для любых натуральных п, т имеет
место равенство НОД (w„, ыт) = ынод<п, m>.
Доказательству предпошлем несколько лемм, в
каждой из которых речь идет о некотором свойстве чисел
Фибоначчи.
Лемма. 1. Пусть р>0, q^\. Тогда
upJ,q = uq_1up + uqup+i. (1)
Доказательство. Индукция по q:
1° пусть <7 = 1. Нужно доказать, что up+i = ueup +
-f-WiUp+i- Это верно, так как ы0 = 0, их = 1;
2° пусть все верно для </ = 1, 2, ..., k. Тогда,
в частности,
ир+к~ uk- Iйр + "*"/>+1>
ир+(к-1) —uk-iup~b~ub-iup+i>
следовательно,
= («*-i + "*-2) "Р+ ("а + «A-i) ",+i -» "*"^ + uk+1up+i.
Задача 3. Убедиться в том, что для корректности
доказательства 2° необходима предварительная проверка, что
утверждение леммы справедливо не только для q=i, но и для q = 2.
Дополнить доказательство!
181
Лемма 2. Для р ^ 1 выполнено НОД (ир, ир„ J = 1.
Доказательство. Индукция по р:
Г если р = \, то ир=\, ир^1 = 0 — все правильно;
2° пусть все верно для р=1, 2, ..., k. Тогда
каждый общий делитель uk+i и ик делит мй_1, так
как Mft-1 = «ft+i—«ft. Следовательно, каждый общий
делитель uk+i и ий является общим делителем ик и
«ft_](, а они, по предположению индукции, взаимно
просты.
Лемма 3. Пусть р^О, q ^ 1. Тогда
НОД(и,+,, ив) = НОД(и,, и,).
Доказательство. Лемма 1 гарантирует
выполнение равенства (1). На НОД(мр+(?, uq) делится левая
часть этого равенства и второе слагаемое правой части.
Следовательно, делится и первое слагаемое правой
части. Но «?_j и НОД(Мр+17, uq) взаимно просты по
лемме 2, значит, ир делится на HOJX(up+q, uq).
Поскольку uq тоже делится на НОД(и„+а, uq),
получаем, что WOJX(up, uq) делится на НОД(и^+(?, uq).
Теперь докажем, что НОД(ы +e, uq) делится на
\ЮЛ{ир, uq). На НОД(ир, uq) делится правая часть
(1), а значит, и левая часть, т. е. up+q. Очевидно,
что uq делится на НОД(м/,, ич). Следовательно,
НОД (up+q, uq) делится на НОД (u,,, uq).
Получилось, что два исследуемых натуральных
числа делят друг друга, а это влечет их равенство.
Теперь теорема доказывается несложно. Если
т=ап + г, О <г<п, то НОД (ит, ы„) = НОД («„„+„ ип) -
=HOR{u(a_i)n+r, «„) = •• . = НОД(ыг,ы„)=НОД(ы„,ы;.).
Видно, что этот процесс можно продолжить; при этом
каждый раз к индексам и применяется та же
процедура, что и в алгоритме Евклида.
В итоге получается, что
НОД(«и, Ы„)=НОД(ЫНОД(т,«), "„)=:
= НОД («НОД(т, п), 0) =ИнОД(т, п)-
Теорема доказана.
Задача 4. Доказать следующие свойства чисел Фибоначчи:
а) и1-г«2+...+«п = "п+2— 1.
б) и\ — i(„«„_i — u2_x =±1,
В) U\— «rt-l"n + l=± U
182
3. Рекурсивные определения. Рекурсивное
определение строится по тому же принципу, что и
рекурсивный алгоритм—показывается, как объект,
удовлетворяющий определению, может быть построен из
более простых объектов. Некоторые объекты (простейшие)
из подпадающих под определение указываются явно.
В предположении, что уже известно понятие буквы,
можно следующим образом определить понятие
непустого слова:
Г если |—буква, то 1—слово;
2° если Р — слово, и \ — буква, то РЬ,—слово.
Рассмотрев следующий пример, можно оценить
удобство рекурсивных определений.
Для регулирования порядка выполнения операций
в алгебраическом выражении, содержащем числа,
буквы и операции сложения и умножения, часто
употребляются круглые, квадратные и фигурные
скобки. Известно, что на самом деле можно обойтись
одними круглыми скобками. Выражение
а-.Ь{с + 2[х + у(г+1)]} + а(с+х)
можно переписать в виде
а—Ь(с + 2(х+у(г+\)))+а(с+х);
никакие двусмысленности при этом не возникают.
Теперь рассмотрим последовательности круглых
скобок, т. е. слова в алфавите {(,)}, которые могут быть
получены из алгебраических выражений удалением
из них всех знаков, кроме круглых скобок.
Например, выписанное выше выражение даст
последовательность ((( ))) ( ). Такие последовательности будем
называть правильными скобочными выражениями.
Хотелось бы иметь более ясное определение правильного
скобочного выражения — определение, которое можно
было бы использовать для доказательства теорем об
этих выражениях. Дадим рекурсивное определение:
1° ( ) — правильное скобочное выражение;
2° если Р — правильное скобочное выражение, то
(Р)—правильное скобочное выражение;
3° если Р и Q— правильные скобочные
выражения, то PQ — правильное скобочное выражение.
Задача 5. Пользуясь данным определением, доказать, что
если Р и Q — правильные скобочные выражения, то ( ) P(Q)—»
правильное скобочное выражение,
183
Представляет интерес алгоритм, который для
любого слова в алфавите {(,)} позволяет выяснить,
является ли это слово правильным скобочным выражением.
Оказывается, существует сравнительно простой
способ решения этой задачи, так называемый способ
подсчета скобок. Сопоставим слову а в алфавите {(,)},
состоящему из п букв, числовой массив ait a2, ... ап,
заменяя каждую левую скобку на 1, и каждую
правую скобку — на —1. Этот массив назовем
изображением слова а. Имеет место следующая
Теорема. Массив ait а2, ..., ап, at — ±l,
i=»l, 2, .... п является изображением правильного
скобочного выражения тогда и только тогда, когда
а) а1 = \;
б) для каждого k такого, что 1 < k < n, выполнено
в) 2а.-=0-
Прежде чем доказывать эту теорему, отметим, что для ее
практического применения не нужно по слову из алфавита {(,)}
предварительно строить его изображение. Переменная s
первоначально приобретает значение 0, затем мы просматриваем слово
слева направо и всякий раз, встретив левую скобку, прибавляем
к s единицу, а встретив правую скобку—единицу вычитаем.
Теорема утверждает, что мы имеем дело с правильным
скобочным выражением тогда и только тогда, когда значение s все
время неотрицательно и в конце просмотра становится равным
нулю. Весь анализ проводится во время одного просмотра
выражения.
Доказательство. В начале докажем прямое
утверждение теоремы: если массив at, аг, ..., ап
является изображением правильного скобочного
выражения, то выполнены а), б), в). Для этого проведем
индукцию по га:
1° для п=ч1 нет изображений правильных
скобочных выражений, для п = 2 имеем одно изображение:
1, —1 (ясно, что для него выполнены а), б), в));
2° пусть п > 2 и относительно меньших значений
установлено, что для изображений правильных
скобочных выражений выполнены а), б), в). Массив
ait «2, .... ап можно представить либо в виде
1, bu fr2, ..., Ьп, — 1 (m = n —2), либо в виде blt ...
184
..., bm, cu ..., ct (m + l = n) и массивы blt ..., bm
и cit ..., ct являются изображениями правильных
скобочных выражений.
В первом случае
а) 0^=1,
к k-i
б) из k < п следует 2 а,- == 1 + 2 ^/ > °>
1=1 /= 1
п т
в) 2«/=i + 2&,—1 = 1+о—i=o.
Во втором случае
а) ai = &i = l, так как Ъи Ь2, ..., ^ —
изображение правильного скобочного выражения,
к k
б) если £<т, то 2% =2 &/^>0; если m<fc^ra,
i= 1 1= 1
TO
ft m ft
2 a/= 2«/+ 2 a, =ч
m k-nt k-m
»•= i <=i i=i
n m I
в) 2fl/=2^-+2 <?/==o.
i=i i=i i=i
Докажем обратное утверждение теоремы: если
выполнены а), б), в), то массив аи ..., ат является
изображением правильного скобочного выражения.
Проведем индукцию по га:
1° поскольку нет массивов из одного элемента,
для которых выполнено а), б), в), рассмотрим
случай га =2. Единственный массив, для которого
выполнены а), б), в), есть 1, —1. Он является
изображением ( );
2° пусть га > 2 и для значений, меньших чем п,
утверждение доказано. Пусть для ait a2, ..., ап вы-
к
полнены а), б), в). Рассмотрим суммы 2 аь k =
1 = 1
= 2, 3, ..., /г — 1. Все они неотрицательны. Среди
т
них может найтись равная нулю. Пусть 2 «/ = 0. Но
*=i
185
в таком случае для aif a2, ..., ат выполнено а), б)
в); для ага+ь ,.., ап тоже выполнено а), б), в):
m+i m
a) am+i=l, иначе 2 at= 2 а/ + ая+1 = 0—1< 0,
s m • s s
б) при s<n 2 йг-=2«,-+ 2 йг-=2«/>о,
i=/n + l 2=1 • i-m + i i'=i
в) 2 а,= 2 fl/ = 0.
« = m+l i=l
По предположению индукции ai( ..., ат и аи+1, ...
,.., ап являются изображениями правильных
скобочных выражений. В соответствии с пунктом 3°
определения правильного скобочного выражения, то же
самое можно сказать про массив ait a2, ..., ап.
Если для каждого k, такого, что 2^.к^п—1,
k
выполнено 2 ai > О» т0 ясно, что ап = — 1, поскольку
п. га—1
иначе 2 ai— 2ai + an>0- Таким образом, в этом
t=i (=i
случае массив аъ ..., ап представляет собой 1, bit ...
..., 6„_3) —1. Докажем, что для Ьи ..., 6Й_2
выполнены а), б), в):
а) bt — \—иначе at + a2 = 0,
б) 2 */ = 2 af— 1 > 0. поскольку 2 a, > 0,
i=i i-г / = i
в) 2 &/=2 a,—«i--a» = 0-l + l=0.
Теперь остается вспомнить пункт 2° определения
правильного скобочного выражения. Теорема доказана.
Задача 5. Дать рекурсивное определение слова в
алфавите {а, Ь}, которое читается слева направо так же, как и справа
налево. Доказать, что произведение числа букв а на число букв
Ь, входящих в такое произвольное слово—число четное.
ЗАКЛЮЧЕНИЕ
Алгоритмические вопросы в математических теориях
возникали одновременно с самими теориями. Эти
вопросы постоянно входили в круг трудных задач,
которым уделялось значительное внимание исследователей.
В математике, наряду с доказательствами утверждений
высокой общности всегда ценились явные формулы,
позволяющие вычислять одни величины, исходя из
других. Естественно, что потребность в такого рода
решениях математических задач особенно велика у людей,
работающих в технике и нематематических науках,
которые исследуют процессы, описываемые функциями,
системами уравнений и т. д. Алгоритмическое решение
задачи позволяет получать конкретные сведения об
исследуемых процессах.
Изобретение и создание (сразу после второй мировой
войны) больших вычислительных машин сделали весьма
актуальными исследования в области алгоритмической
математики. Такие машины способны выполнять
определенные алгоритмы построения математических
объектов и приходят на помощь в тех исследованиях, где
сведения о некоторых процессах добываются ценой таких
построений (в частности, вычислений), которые, с одной
стороны, описываются алгоритмически, а с другой —
настолько сложны, что их невозможно (или очень трудно)
осуществить вручную.
Правила описания алгоритмов для выполнения
машиной всегда оказываются очень жесткими. Это
понятно — алгоритм будет выполнять автомат, который не
может ничего додумывать за человека, составившего
неясный алгоритм. Мы до сих пор придерживались такой
формы записи алгоритмов, которая иногда включала в
187
себя пояснения на русском языке. При употреблении
конструкций русского (как и любого другого
естественного) языка, мы не застрахованы от двусмысленностей и
неточностей. Так что, скорее всего, такая форма записи
не будет пригодной ни для одной из машин.
Условимся называть совокупность средств и правил
записи алгоритмов алгоритмическим языком. От
алгоритмического языка прежде всего требуется, чтобы
написанное на нем понималось однозначно. Алгоритм,
описанный на понятном некоторой машине алгоритмическом
языке, называется программой. Соответственно говорят о
программировании — роде человеческой деятельности,
заключающемся в создании программ. Программист
вынужден преодолевать трудности, возникающие именно
вследствие того, что плод его труда — программа — будет
выполняться машиной. Эти трудности не возникли бы
при рассмотрении только вопроса существования
алгоритма. Машина обладает ограниченной памятью.
Некоторые программы при определенных исходных
данных не могут быть выполнены из-за слишком большого
количества величин, возникающих в процессе
выполнения. Такие программы приходится переделывать.
Помимо этого, на выполнение программы уходит время.
Сколь бы быстро ни работала машина, для выполнения
некоторых программ может потребоваться время,
слишком большое для того, чтобы считать его приемлемым
(например, тысяча лет).
Конструкции вычислительных машин постоянно
совершенствуются. В частности, появляются машины,
обладающие все большим быстродействием и памятью.
Алгоритмы, бывшие практически непригодными для
старых машин, могут с появлением новых машин
начать приносить какую-то пользу. Но разработка нового
экономного алгоритма может дать для решения какого-
то класса задач больше, чем изобретение машины,
быстродействие и память которой увеличатся во много
раз в сравнении с прежним уровнем. Так может
случиться, например, когда удается перейти от алгоритма с
линейной трудоемкостью к алгоритму с логарифмической
трудоемкостью.
В этой книге к алгоритмам постоянно применялись
требования экономности: экономилось место для записи
величин (память), экономилось количество операций.
Это сближает дух книги с программированием. Еще одно
188
сближающее обстоятельство. В программировании
придерживаются точки зрения, близкой к принятой нами в
первых разделах книги: очерчивается круг объектов и
набор допустимых операций. Требуется составить такой
алгоритм построения объекта, который использует только
операции данного набора. Программист в известной мере
не интересуется тем, как будут выполняться эти
операции. Ему разрешили пользоваться операциями — он и
пользуется. Близость нашего подхода к
программистскому оправдывает название книги.
Машина может понимать несколько алгоритмических
языков. Один из этих языков может предназначаться
для алгоритмов вычислительного (арифметического)
характера, другой — для обработки слов в некоторых
алфавитах, третий v- для алгоритмов преобразования
геометрических объектов и т. д. Но конструкция
машины такова, что в любом случае обработка данных и
построение результата проводится путем действий со
словами в фиксированном алфавите (чаще всего в
алфавите {0, 1}). Объекты другого вида некоторым образом
заменяются такими словами. В связи с этим говорят о
«представлении объекта в памяти машины». Программист
может не интересоваться этим обстоятельством —
исходные данные и ответ будут по виду объектами той
природы, на которую рассчитан язык. Но ему не уйти
от того, что это обстоятельство сделает в некоторых
случаях результат выполнения алгоритма не вполне
точным.
Выполнение каких-то из допустимых арифметических
операций может привести, по математическому
определению этих операций, к возникновению
иррациональных чисел. В то же время каждое число представляется
в машине конечным набором цифр. В процессе
выполнения алгоритмов, слагающихся из подобных операций,
неизбежны погрешности. Некоторые вычисления и
построения становятся приближенными. Можно
представить себе, например, что иррациональные числа
заменяются достаточно хорошо их приближающими
рациональными.
Часто в этим можно примириться, потому что на
самом деле и не требуется абсолютно точного решения. Если
число, которое ожидается получить в результате
применения алгоритма, будет истолковано как количество
тонн песка, необходимое для перевозки в грузовике из
189
одного пункта в другой, то точный ответ ]/~2 будет
ничуть не лучше (и даже скорее всего хуже), чем 1,41.
Встречаются задачи (логические, комбинаторные),
когда с приближенностью мириться нельзя. Решение
подобных задач, как правило, возможно, так как
некоторые операции производятся машиной абсолютно точно.
Приближенность возникает, как правило, при
оперировании с действительными числами, точками плоскости и
т. д. Действия со словами, целыми числами и тому
подобными объектами приводят к точным результатам.
Если нельзя заменять иррациональные числа
рациональными приближениями, то естественно пытаться
строить ответ не в числовом виде, а в виде формулы
(вроде У~2).
Некоторые алгоритмические языки позволяют
действовать с формулами, изображаемыми словами
определенного алфавита. Если язык не таков, то может быть
удастся заменить саму формулу специальным кодом,
скажем, массивом целых чисел.
Когда ставится цель создать алгоритмический язык,
который будут понимать вычислительные машины, то
стремятся дать богатые средства ясного описания
алгоритмов, позволяющие применять близкую к принятой в
математике систему обозначений.
В этой книге алгоритмы записывались в форме,
которая отличается (хотя и не сильно) от принятой в
современных алгоритмических языках. Этой форме несколько
недостает четкости. Она привлекалась для того, чтобы
на первых порах можно было не заниматься сугубо
формальными вещами, а сосредоточиться на
алгоритмической сущности математических задач. Эта форма
обладает рядом достоинств. Во-первых, она отчасти
использует конструкции, присущие современным
алгоритмическим языкам. Во-вторых, она легко может быть
доведена до должного уровня четкости. В-третьих,
можно надеяться, что человек, знающий некоторый
настоящий алгоритмический язык, сможет легко
переработать наши алгоритмы в программы.
Читателям, не знакомым ни с одним из
алгоритмических языков, можно порекомендовать начать с языка
АЛГОЛ 60. Он был разработан в 1960 году группой
западноевропейских и американских ученых, а
впоследствии приобрел широкое распространение во всех
странах мира.
190
Изложение наиболее существенной части АЛГОЛа 60,
не предполагающее у читателя никакой специальной
подготовки, можно найти в книге:
А б р а м о в С. А., А н т и п о в И. Н.,
Программирование на упрощенном алголе, М., «Наука», 1978.
Обстоятельному изложению языка посвяаиша книга:
Л а в р о в С. С, Универсальный язык
программирования, М., «Наука», 1972.
Читателям, интересующимся более современными
языками, можно рекомендовать книги:
Бауэр Ф., Г о о з Г., Информатика, М., «Мир»,
1976.
В и р т Н., Систематическое программирование,
введение; М., «Мир», 1977.
В последних двух книгах можно также найти многое
о задачах и методах современного программирования.
Сергей Александрович
Абрамов
МАТЕМАТИЧЕСКИЕ ПОСТРОЕНИЯ
И ПРОГРАММИРОВАНИЕ
М., 1978 г., 192 стр. с илл.
Редактор И. А. Д ж е м и с ю к.
Техн. редактор С. Я. Ш к л я р.
Корректор Л. С. Сомова.
ИБ № 2336
Сдано в набор 30.12.77. Подписано к печати
17.04.78. Т-08234. Бумага 84X108'/»» тип.
М 3. Литературная гарнитура. Высокая печать.
Услови. печ. л. 10,08. Уч.-изд. л. 10,06.
Тираж 100 000 экз. Заказ Л° 2243, Цена книги
30 коп.
Издательство «Наука»
Главная редакция
физико-математической литературы
117071, Москва, В-71, Ленинский проспект, 15
Ордена Октябрьской Революции
и ордена Трудового Красного Знамени
Первая Образцовая типография
имени А. А. Жданова Союзполиграфпрома
при Государственном комитете
Совета Министров СССР по делам издательств<
полиграфии и книжной торговли.
Москва, М-Б4, Валовая, 28