Программирование игр и головоломок
Шрифт:
Если вы решили оставить Тони шансы на спасение, действуйте, как в предыдущей программе. Вы случайным образом выбираете путь и обозначаете его так, чтобы никакое препятствие на него сверху не падало. Но вы не выводите на экран этих обозначений.
2. Игры с числами
Головоломка 3.
Я нашел это упражнение в монографии, посвященной языку Пролог. Предложенное там решение действует методом проб и ошибок. Но задача решается намного проще.
Как всегда, полностью определим задачу. Искомое число представляется в десятичной системе последовательностью цифр
cncn– 1…c25
Умножая
5cncn– 1…c3c2
Отсюда следует, что c2 = 5. Все цифры ci точно так же итеративно вычисляются справа налево, обыгрывая оставшееся от предыдущего умножения «в уме»: когда вы умножаете крайнее справа 5 на 5, вы получаете 5 единиц, что и дает c2 = 5, и 2 «в уме». Тогда вы можете вычислить c3 и новую цифру «в уме» и продолжать шаг за шагом. Остается маленькая задача о том, как узнать, когда следует остановиться. Изучите ее сами; как обычно, я не хотел бы сообщать вам все…
Вы можете также действовать слева направо:
5cncn– 1…c3c2 : 5 = cncn– 1…c25
Деля левую цифру на 5, вы получаете cn = 1. Имея cn, вы можете продолжать деление. И здесь тоже вам нужно будет принимать во внимание перенос результата, полученного при предыдущем делении, и нужно будет знать, когда остановиться. Эти два метода по существу равносильны.
Остальное оставляю исследовать вам.
Головоломка 4.
Обычно я бываю глубоко разочарован тем, что нахожу в книгах по информатике или по математике касательно квадратных корней. Чаще всего вам предлагают метод Ньютона: пусть вам нужно извлечь квадратный корень из числа x. Вы образуете возвратную последовательность ui по правилу
ui+1 = (ui + (x/ui))/2.
Вне всякого сомнения, вы можете взять u0 = 1 в качестве начального значения. Эта последовательность очень быстро сходится к квадратному корню из x. Если, например, взять x = 50 и воспользоваться формулой
ui+1 = целая_часть ((ui + (x/ui))/2),
чтобы иметь дело только с целыми
числами, то в качестве последовательных значений и вы получитеu0 = 1, u1 = 25, u2 = 13, u3 = 8, u5 = 7, u6 = 7.
Чтобы использовать здесь этот алгоритм, вы должны написать программу целочисленного деления двух целых чисел большой длины.
Другой способ действия основан на том факте, что разность двух последовательных квадратов есть нечетное число:
(n + 1)^2 - n^2 = 2n + 1,
так что последовательные разности являются последовательными нечетными числами. Поэтому можно видеть, что сумма нечетных чисел от 1 до 2k– 1 включительно есть k^2. Обратно, если вычитать из n последовательно возрастающие числа, пока это возможно (не допуская, чтобы результат становился отрицательным), тогда искомый квадратный корень есть к, если последнее нечетное вычитаемое равно 2k– 1. Таким образом, для 50
50 - 1 = 49,
49 - 3 = 46,
46 - 5 = 41,
41 - 7 = 34,
34 - 9 = 25,
25 - 11 = 14,
14 - 13 = 1.
Нельзя продолжать, не получая отрицательной разности. Последнее нечетное вычитаемое равно 13, поэтому корень есть (13 + 1)/2 = 7 (и остаток 1). Этот способ гораздо лучше подходит для распространения на случай очень больших чисел, потому что вам требуется реализовать только две операции:
— прибавить 2 к большому числу;
— вычесть одно большое число из другого.
Но число шагов цикла равно искомому квадратному корню, а он может оказаться весьма большим.
Можно обобщить предыдущий алгоритм, используя свойства десятичной записи чисел. Данное число разделяется на куски по две цифры, начиная справа; затем мы начинаем вычитать последовательные нечетные числа из крайнего слева куска:
Если это нельзя продолжать дальше, то последнее вычитаемое число увеличивается на единицу, сдвигается на один шаг вправо, и следом за ней приписывается единица. Это — первое нечетное число, которое следует вычитать из предыдущего остатка.
В приведенном выше примере 7 + 1 = 8; приписывая 4, получаем 81 и продолжаем:
Поскольку продолжать дальше нельзя (последнее возможное вычитание из остатка — это крайнее справа), то последнее из вычитаемых чисел нужно увеличить на 1, а затем разделить на 2, чтобы получить корень. Последний остаток и есть остаток квадратного корня:
85 + 1 = 86, 86/2 = 43,
1909 = (43)2 + 60.
Этот алгоритм достаточно прост для программирования при длинных числах, и он дает вполне разумное время вычисления.
У вас много возможностей представлять свои данные. Так как мы оперируем с кусками из двух цифр, то вы можете задавать свои данные таблицами целых чисел в интервале от 0 до 99.
Вы можете представлять свои целые числа как цепочки символов, где используются только числовые символы (цифры) от 0 до 9. Выбор способа зависит от ваших предпочтений и от возможностей вашей машины оперировать с таблицами и цепочками. Тщательно рассмотрите, какие операции нужно сделать. Вы ничем не ограничены: почему бы не запрограммировать и сравнить два разных решения?