Читаем Программирование игр и головоломок полностью

Наконец, a, начиная с 4, умножается на 2 при каждом прохождении цикла; b начинается с 1, которое меньше соответствующего начального а = 4.

Тогда при переходе от a, b, p к a', b', p' либо

b' = b, а' = 2*а, так что если b а, то и b' а';

либо

b' = а + b, а' = 2*а, что также сохраняет справедливость отношения а' b'.

Следовательно, вот ситуация, которую цикл оставляет инвариантной:

n = а*p + b2;

а — степень двойки,

p четно,

b нечетно, b а.

Кроме того, мы знаем, что при выходе из цикла p а.

Если p равно нулю, то n = b2. Тогда мы видим, что n — квадрат числа b, которое выводится, и все закончено.

Но n может оказаться полным квадратом и тогда, когда p не нуль. Попробуем рассмотреть все возможные случаи. Положим n = r2 (r нечетно). Соотношение

r2 = ар + b дает

r2 - b2 = ар.

Положим r + b = 2u, r - b = 2v (r и b нечетны). Отсюда получаем 4uv = ар.

Поскольку r = u + v, где r нечетно, получаем, что u и v не могут быть числами одинаковой четности, так что одно из них четно, а другое нечетно. Так как а является степенью двойки, то нечетный сомножитель относится к p. Выявим его, полагая р = s2t, где s нечетно, a t >= 1 (p четно).

Напомним, что а = 2k. В этих обозначениях 4uv = ар = s2k+t, uv = s2k+t-2.

Возможные решения для пары u, v имеют вид пар

s'2k+t-2, s''

где s's" = s.

Покажем сначала, что s" — меньший из этих двух элементов пары. Вследствие t >= 1 имеем k - t = k + t - 2.

Вследствие p а последовательно выводим

s2t 2k,

s's"2t 2k.

s's" 2k-t = 2k+t-2 = s'22k+t-2

(потому что s' нечетен и не меньше 1).

Следовательно, нужно взять u = s'2k+t-2, v = s".

Покажем теперь, что нужно обязательно взять s' =1, s" = s. По выбору u и v

b = 2k+t-2s' - s" а = 2k.

Отсюда получаем:

s" 2k+t-2s' - 2k,

и, так как t >= 1:

s" 2k-1s' - 2k,

s = s's" 2k-1s'2 - 2ks = 2k-1s' (s' - 2).

Вследствие р = s2t а = 2k выводим s 2k-t = 2k-1.

Объединим два полученных неравенства:

2k-1s' (s' - 2) x 2k-1, поэтому s' (s' - 2) 1.

Единственное нечетное число s', удовлетворяющее этому соотношению, это s' = 1. Следовательно, у нас остается единственная возможность:

u = 2k+t-2, v = s,

b = u - v = 2k+t-2 - s а = 2k,

s 2k+t-2 - 2k.

Так как s 2k-t, то t должно быть таким, чтобы

2k-t 2k+t-2 - 2k.

Поскольку t должно быть строго положительно, то его единственными возможными значениями являются t = 1 и t = 2.

При t = 1 имеем

p = 2s, b = 2k-t - s = a/2 - p/2.

Следовательно, если 2b = а - p, то n — квадрат числа (а + p)/2 = а - b.

При t = 2 имеем

p = 4s, b = 2k - s = a - p/4.

Следовательно, если p = 4(a - b), то n — квадрат числа a + p/4 = 2а - b.

Этим исчерпываются случаи, когда n может быть полным квадратом.

Можно спросить себя, могут ли эти различные случаи действительно осуществляться. Заметим, что при вступлении в цикл у нас b = 1, a = 4. После этого b может быть изменено добавлением а, т. е. кратным числа 4. Следовательно, b остается сравнимым с 1 по модулю 4. В трех возможных случаях:

p = 0, r = b,

p = а - 2b, r = a - b,

p = 4 (a - b), r = 2a - b,

первый случай — единственный, в котором квадратный корень из n сравним с 1 по модулю 4; два других дают квадратный корень, сравнимый с 3 по модулю 4. При выходе из цикла равенство

b = ар + b2

с учетом соотношений p a, b a дает n 2a2 и, следовательно, при выходе из цикла a2 n/2. Равенство

ар = n - b2

дает p = (n - b2)/a n/а.

Если окажется, что n/а a, то непременно p а и цикл закончен. Чтобы цикл остановился, необходимо, чтобы a2 n/2, и цикл заведомо останавливается, если a3 n.

Следовательно, все зависит от положения n по отношению к степеням двойки. Существует такое целое n, что

4q n 4q+1.

Возможны два случая. Во-первых, может выполняться неравенство

4q = 22q n 22q+1,

и тогда для k = q число a2 = 22q n/2 может быть значением остановки, но в этом нет уверенности. С другой стороны, если

22q+1 n 22q+2,

то единственное значение a, удовлетворяющее условию a2 n/2, есть a = 2q+1, и для этого значения имеем a2 n, что гарантирует остановку. Поскольку r = a - b, то а = r + b r и, следовательно, a2 n.

Во втором случае

r = 2a - b и b а, откуда а 2a - b = r.

Таким образом, все три распознаваемые программой случая являются единственными возможными исходами программы, и каждый из них может произойти.

Таким образом, перед нами — очень забавный алгоритм, который дает значение квадратного корня, и который определяет случай, когда n не является корнем, но в этом случае не дает никакой дополнительной информации.

Программа заведомо останавливается при а = 2q+1, так что число шагов цикла не больше q - 1 (начиная с 4), причем q — логарифм квадратного корня из n по основанию 2. Таким образом, получилась программа порядка In n, что дает ту же сложность, что и обычный алгоритм, действующий кусками по две цифры. Но для этого последнего алгоритма нужен еще первый цикл, чтобы найти порядок величины n.

Головоломка 19.

Соотношение f(a, b) = f(b, a) следует из самой инициализации p и q:

p := max (a, b); q := min (a, b).

Перейти на страницу:

Похожие книги

Основы программирования в Linux
Основы программирования в Linux

В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стан­дартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым. Для начинающих Linux-программистов

Нейл Мэтью , Ричард Стоунс , Татьяна Коротяева

ОС и Сети / Программирование / Книги по IT
97 этюдов для архитекторов программных систем
97 этюдов для архитекторов программных систем

Успешная карьера архитектора программного обеспечения требует хорошего владения как технической, так и деловой сторонами вопросов, связанных с проектированием архитектуры. В этой необычной книге ведущие архитекторы ПО со всего света обсуждают важные принципы разработки, выходящие далеко за пределы чисто технических вопросов.?Архитектор ПО выполняет роль посредника между командой разработчиков и бизнес-руководством компании, поэтому чтобы добиться успеха в этой профессии, необходимо не только овладеть различными технологиями, но и обеспечить работу над проектом в соответствии с бизнес-целями. В книге более 50 архитекторов рассказывают о том, что считают самым важным в своей работе, дают советы, как организовать общение с другими участниками проекта, как снизить сложность архитектуры, как оказывать поддержку разработчикам. Они щедро делятся множеством полезных идей и приемов, которые вынесли из своего многолетнего опыта. Авторы надеются, что книга станет источником вдохновения и руководством к действию для многих профессиональных программистов.

Билл де Ора , Майкл Хайгард , Нил Форд

Программирование, программы, базы данных / Базы данных / Программирование / Книги по IT
Программист-прагматик. Путь от подмастерья к мастеру
Программист-прагматик. Путь от подмастерья к мастеру

Находясь на переднем крае программирования, книга "Программист-прагматик. Путь от подмастерья к мастеру" абстрагируется от всевозрастающей специализации и технических тонкостей разработки программ на современном уровне, чтобы исследовать суть процесса – требования к работоспособной и поддерживаемой программе, приводящей пользователей в восторг. Книга охватывает различные темы – от личной ответственности и карьерного роста до архитектурных методик, придающих программам гибкость и простоту в адаптации и повторном использовании.Прочитав эту книгу, вы научитесь:Бороться с недостатками программного обеспечения;Избегать ловушек, связанных с дублированием знания;Создавать гибкие, динамичные и адаптируемые программы;Избегать программирования в расчете на совпадение;Защищать вашу программу при помощи контрактов, утверждений и исключений;Собирать реальные требования;Осуществлять безжалостное и эффективное тестирование;Приводить в восторг ваших пользователей;Формировать команды из программистов-прагматиков и с помощью автоматизации делать ваши разработки более точными.

А. Алексашин , Дэвид Томас , Эндрю Хант

Программирование / Книги по IT