Flat Preloader Icon

Project Euler (answers)

Проект Эйлера: Ответ и решение 30 задачи (Пятые степени цифр)

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

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

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

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

1634 = 14 + 64 + 34 + 44
8208 = 84 + 24 + 04 + 84
9474 = 94 + 44 + 74 + 44

1 = 14 не считается, так как это – не сумма.

Сумма этих чисел равна 1634 + 8208 + 9474 = 19316.

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

Всегда Вам рады))

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

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

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

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

Описание алгоритма программы

Алгоритм работы программы в точности соответствует приведенному  заданию:

  • Перебираются натуральные числа.
  • Каждое число раскладывается на отдельные цифры.
  • Каждая цифра числа возводится в пятую степень тем или иным способом (например, функцией pow()).
  • Если сумма цифр в пятой степени окажется равной числу в итоге, тогда добавляем проверяемое число к ответу.

Данный алгоритм, конечно, тоже дает правильный ответ, однако его возможно ускорить

Определяем максимально возможное число (первое улучшение программы)

Перед началом работы программы возникает вопрос: до какого числа искать ответ (MAX_NUM – смотрите скриншот выше)?

  • for (int number = 2; number <= MAX_NUM; number++)

Можно, конечно, постепенно увеличивать MAX_NUM:

  • 1000 -> 10000 -> 100000 -> 1000000

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

Ход рассуждений будет следующим.

Максимальной цифрой в любом месте числа будет девятка. 9^5 = 9*9*9*9*9 = 59049. Потому:

  • Число из одной цифры (9) дает 9^5 = 59049.
  • Из двух цифр (99) соответственно 9^5 + 9^5 = 118098
  • Трехзначное (999) -> 3 *9^5 = 177147
  • Четырехзначное (9999) -> 4*9^5 = 236196
  • Пятизначное (99999) -> 5*9^5 = 295235
  • Шестизначное (999999) -> 6*9^5 = 354294
  • Семизначное (9999999) -> 7*9^5 = 413343

Таким образом видно, что даже максимально возможное семизначное число (9999999) в итоге дает только шестизначное (413343).

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

Более того, потому оно и не может быть более 6*9^5 = 354294.

В итоге, уточнение диапазона поиска сокращает объем вычислений (относительно 1000000 – в три раза).

Функция для возведения числа в степень (проект Эйлера - 30 задача)

Функция для возведения числа в степень
Функция для возведения числа в степень

Второе ускорение алгоритма

В стандартной библиотеке math.h, есть функция pow() для возведения числа в степень. Данная функция обладает обширными возможностями, может возводить в дробные и отрицательные степени, например. Однако за счет расширенной функциональности, работает она медленней, чем могла бы.

В нашем случае нам нужно всего лишь возводить натуральные числа в натуральные степени. Потому в функции число просто перемножается само на себя нужное количество раз (смотрите скриншот). 

В итоге, применение такой облегченной и урезанной функции pow() при прочих равных ускорило работу программы на порядок.

Третье ускорение алгоритма

Поскольку нам необходимо возводить только в пятую степень и только цифры от 0 до 9, потому вычислим эти значения и сохраним в массив (смотрите выше).

  • arr[3] = 243; // номер ячейки – число (3), значение в ячейке – степень числа (3^5)

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

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

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

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

  • #include <time.h> 

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

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

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

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

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

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

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

В итоге ответ на 30 задачу проекта Эйлера составил 443839, программа считает ответ мгновенно (изначальный алгоритм тратил 0.3 секунды). 

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

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

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

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

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

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

© 2023-2024 | eulerproject.ru