Flat Preloader Icon

Project Euler (answers)

Проект Эйлера: Ответ и решение 15 задачи (Пути через таблицу)

Проект Эйлера (15 задача) – на первый взгляд очень простая, однако поиск действительно эффективного алгоритма заставил поломать голову

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

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

Начиная в левом верхнем углу сетки 2×2 и имея возможность двигаться только вниз или вправо, существует ровно 6 маршрутов до правого нижнего угла сетки.

Проект Эйлера 15 задача (задание)
Проект Эйлера - 15 задача (задание)

Сколько существует таких маршрутов в сетке 20×20?

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

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

В программе мы посчитаем количество вариантов попасть в каждый узел сетки. В итоге мы получим количество маршрутов от верхнего левого до  нижнего правого угла сетки.

Для понятного примера возьмем сетку с ячейками 2 x 2 и преобразуем ее в граф с вершинами в узлах сетки 3 x 3. Для понятности все нарисовал (рисунок 1).

Проект Эйлера 15 задача (алгоритм решения)
Проект Эйлера 15 задача (алгоритм решения)

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

Рисунок 1: узел a (левый верхний угол сетки) – это начало движения, узел (правый нижний угол) – конец.

  • Рисунок 2: при любом маршруте в узел a можно попасть только одним способом, потому что отсюда по условию нужно начинать. В узлы b и c также можно попасть только одним маршрутом (слева направо).
  • Рисунок 3: в узлы d и g можно попасть также одним способом (сверху вниз)
  • Рисунок 4 поясняет суть алгоритма. Во всех остальные точки, кроме крайне левых и верхних можно попасть как сверху так и слева. Попасть в точку e можно попасть из точки b (сверху) и из точки d (слева). При этом ранее посчитано, что в точку a можно попасть одним маршрутом, и в b – одним. Потому, сложив маршруты до них (1 + 1) мы получим 2 маршрута до точки e.
  • Рисунок 5: точка b (1 маршрут) + точка e (2 маршрута) и в итоге до точки f можно добраться 3 маршрутами.
  • Ход рассуждений дальше идет так же и на рисунке 7 видно, что до точки k (правый нижний угол) можно добраться маршрутами, как и было в условиях задачи.

В итоге можно вычислить количество маршрутов до точки как сумму маршрутов до точки сверху и точки слева.

Добавляем вспомогательный столбик слева

Рисунок 8: чтобы автоматизировать расчеты нужно заполнить начальные данные. Потому первый ряд – точки a b c заполнил единицами (1 возможный маршрут). Также добавим дополнительный (нулевой) столбик слева от первого столбца – a d g и заполнил его нулями (туда нельзя попасть).

Это позволяет по одной формуле вычислять все остальные точки, например, точка d вычисляется как 0 + 1 (рисунок 8).

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

Проект Эйлера - 15 задача (решение)
Проект Эйлера - 15 задача (решение)

Представляем сетку 20 x 20 клеток как граф 21 x 21 вершин, добавим к нему столбик с нулями слева и получится граф 21 x 22.

Можно создать двумерный массив [21][22] для хранения вершин графа. Однако для решения задачи вполне достаточно одного ряда узлов – массива длиной [22]. В него последовательно будут перезаписываться данные всех рядов.

  • long long knot_row[22] = {0};

Сначала зададим начальные данные. Левый верхний узел имеет координату в массиве [1] и попасть в него можно только единственным путем.

  • knot_row[1] = 1;

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

  • Первый ряд: [0,1,1,1,1,1… 1]

Это абсолютно верно, потому что в него можно попасть единственным путем – слева. Напомню, что левый столбик с координатой [0] добавлен как вспомогательный. Его значение нулевое, потому что попасть туда нельзя.

На второй итерации цикла for() будет вычисляться второй ряд. При этом данные первого ряда в массиве будут использоваться и перезаписываться данными второго ряда. Потом третий и так далее.

В итоге, если печатать данные массива одновременно с их вычислении, то получится следующая картина:

  • 0 1 1 1 1 1 1…
  • 0 1 2 3 4 5 6…
  • 0 1 3 6 10… 

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

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

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

  • #include <time.h> 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

© 2023-2024 | eulerproject.ru