Flat Preloader Icon

Project Euler (answers)

Проект Эйлера: Ответ и решение 36 задачи (Двухосновные палиндромы)

Проект Эйлера (36 задача). Просто перебрать и проверить все числа до миллиона вполне возможно, однако лучше сразу получать палиндромы.

Узнать больше в телеграм-канале: ProjectEuler++

Условия задачи

Десятичное число 585 = 10010010012 (в двоичной системе), является палиндромом по обоим основаниям.

Найдите сумму всех чисел меньше миллиона, являющихся палиндромами по основаниям 10 и 2.

(Пожалуйста, обратите внимание на то, что палиндромы не могут начинаться с нуля ни в одном из оснований).

Добро пожаловать на сайт))

Решение (проект Эйлера - 36 задача)

Проект Эйлера (36 задача) - решение, часть 1
Решение, часть 1

Поскольку функция main() получилась объемной, потому чтобы не “мельчить”, решил разбить ее на два скриншота.

Проект Эйлера (36 задача) - решение, часть 2
Решение, часть 2

Получаем палиндромы

Первое же улучшение, которое приходит в голову, глядя на условие задачи – это получать сразу палиндромы. Потому что иначе при переборе понадобится проверить 1000000 чисел.

Если же получать палиндромы, просто используя цифры одного числа зеркально:

  • 1 -> 11
  • 23-> 3223
  • 456-> 654456

… то понадобится перебрать числа только до 1000. Что в итоге сократит вычислений сразу на три порядка.

Однако зеркальным удвоением числа можно получить только палиндромы с четным количеством цифр в числе.

Как получать числа вида?:

  • 12321
  • 252

Их можно получать перебором двух чисел: одной центральной цифры (от 0 до 9) и двух зеркальных чисел по краям (от 1 до 99).

Этот перебор 10 цифр на 100 в итоге даст еще 1000 комбинаций. Однако это опять-таки сильно меньше первоначального миллиона.

В итоге в программе перебираются все возможные палиндромы по основанию 10.

Проверка палиндромов по основанию два

Поскольку палиндромы по основанию 10 мы получаем сразу, потому их остается только проверить на “палиндромность” по основанию 2. Соответственно напрашиваются и битовые операции для этой проверки.

Подробнее об алгоритме – ниже в описании соответствующих функций.

Измеряем время работы программы

Для измерения времени работы программы подключаем библиотеку time.h:

  • #include <time.h> 

С помощью функции clock() измеряем время начала (begin) и окончания (end) работы программы. В итоге время работы будем находить как разность между ними.

* Примечания:

clock_t это тип данных, определенный через typedef. По сути это обычный целочисленный long

(double) приводит число (в данном случае – результат вычислений end – begin) к вещественному типу данных double (числа с точкой)

CLOCKS_PER_SEC – это константа, сохраненная в библиотеке и зависящая от типа устройства, на котором запускается программа. В данном случае – это просто 1000

Функции, использующиеся в программе (проект Эйлера - 36 задача)

Проект Эйлера (36 задача) Функция для получения палиндрома (с четной длиной числа) из числа
Функция для получения палиндрома (с четной длиной числа) из числа

Функция для получения палиндрома (с четной длиной числа) из числа

Данная функция получает из исходного числа большее, с цифрами, расположенными зеркально.

На первом этапе определяется порядок числа. Множитель (fact) увеличивается до тех пор, пока не достигнет нужного порядка:

  • Число 123 -> fact = 1 -> 10 -> fact = 100

Далее исходное число раскладывается на цифры и  с помощью двух вспомогательных множителей формируются две половины палиндрома.

Один множитель (f_less) уменьшается (от 100 до 1) и формирует  меньшую половину:

  • Из числа 123 получается 321

Второй (f_more) увеличивается (от 1000 до 100000) и формирует большую половину числа:

  • 123 -> 123000

Их сумма в итоге образует искомый палиндром.

Функция для получения палиндрома (с нечетной длиной числа) из двух чисел

Функция для получения палиндрома (с нечетной длиной числа) из двух чисел
Функция для получения палиндрома (с нечетной длиной числа) из двух чисел

Похожая на предыдущую функция. Тут также на первом этапе формируется множитель, однако, в этот раз, на порядок больший числу.

Например, формируем палиндром на основе 3 и 12.

Тогда для числа 12 будет сформирован множитель fact = 100. Так происходит, потому что с его помощью должна получиться средняя цифра будущего палиндрома. 

3 в итоге станет 300 и встанет ровно в середину пятизначного числа.

Точно так же как и в предыдущей функции, из исходного числа формируются большая и меньшая части:

  • 12 -> 21 меньшая
  • 12 -> 12000 большая

Сумма всех трех чисел в итоге сформирует искомый палиндром:

  • 12000 + 300 + 21 = 12321

Функция для проверки, является ли палиндромом число по основанию 2

Проект Эйлера (36 задача) Функция для проверки, является ли палиндромом число по основанию 2
Функция для проверки, является ли палиндромом число по основанию 2

Напомню, что десятичные числа в двоичном вид представляют собой ряд нолей и единиц. Возьмем пример из задания:

  • 585 = 10010010012

С двоичными операциями можно совершать ряд действий.

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

  • 585 << 1 = 10010010012 << 1 = 100100100102

То же самое, однако теперь все биты сдвигаются вправо. Крайне правый бит теряется:

  • 585 >> 1 = 10010010012 >> 1 = 1001001002

Побитовое “И“. Два числа сравниваются побитно и 1 будет только в тех битах, в которых в обоих числах стояло 1:

  • 585 & 1 = 10010010012 & 00000000012 = 00000000012  (т.е. 1)

Алгоритм функции в итоге следующий:

  • с помощью побитового “И” мы берем остаток числа (number) и заносим его в число palindrome.
  • остаток от числа отрезается (number >>= 1);
  • биты числа-палиндрома смещаются влево (palindrome << 1) и берется следующий остаток.

Число number в итоге постепенно уменьшается:

  • 10010010012 ->1001001002 ->100100102

А palindrome постепенно растет:

  • 12 ->102 ->1002

Их совпадение в итоге и будет признаком, что исходное число – палиндром.

Ответ и скорость работы программы (проект Эйлера - 36 задача)

Проект Эйлера (36 задача) - ответ
36 задача ответ

В итоге ответ на 36 задачу проекта Эйлера составил 872187, при этом программа считает ответ достаточно мгновенно. 

По традиции хотелось бы выразить глубочайшую признательность Сергею Балакиреву за его титанический труд по созданию бесплатных курсов и в частности, за “Язык программирования C/C++ для начинающих“.

проект Эйлера
Курс "C/C++ для начинающих"

Есть вопросы, господа? Отвечаем спокойно, четко и только по делу))

Есть вопросы, господа?

Проект Эйлера (ответы) | © 2023-2024 | eulerproject.ru

Проект Эйлера (ответы) | © 2023-2024 | eulerproject.ru

© 2023-2024 | eulerproject.ru