Найти тему
ZDG

Проект Эйлер 15: Пути через таблицу

Оглавление

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

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

Решение

Размер сетки не имеет никакого значения, поэтому для простоты разберём на примере 2*2.

Маршрут должен вести из левого верхнего угла в правый нижний. Между этими углами по горизонтали 2 шага и по вертикали 2 шага.

Значит, маршрут состоит из 4-х шагов, где 2 шага обязательно горизонтальные и 2 шага обязательно вертикальные. Вот возможные комбинации этих шагов:

ГГВВ, ГВГВ, ГВВГ,
ВВГГ, ВГВГ, ВГГВ

В общем случае нам нужно найти количество комбинаций из N элементов одного типа и M элементов другого типа. Это типичная задача комбинаторики, поэтому можно смело гуглить формулу:

-2

В данной формуле 40 это общее количество элементов (n), а 20 это количество элементов одного из типов (k, соответственно все остальные будут другого типа).

Ответ получен даже без программного кода

Но если эту задачу именно программировать, мы встретим один подвох, а именно вычисление факториалов. Проблема в том, что 40! это ОЧЕНЬ большое число, которое не помещается даже в 64 бита.

Поэтому выходы здесь такие:

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

У нас тут 40! делится на 20!, а потом ещё раз делится на 20!.

Первое деление 40! / 20! сокращается так, что остаётся только произведение чисел с 21 по 40, в связи с чем я модифицировал функцию вычисления факториала, чтобы она считала его не с 1.

Но факториал (21..40) всё равно громадное число. Второе деление уже так просто не сократишь, но очевидно, что в 20! есть множители, на которые делится (21..40)!.

Поэтому я просто на каждом шаге вычисления 40! добавил проверку на деление одним из множителей 20!, так что текущее произведение всё время делится на доступные множители и поэтому не может сильно вырасти. Уже использованные множители помечаются в массиве divs, чтобы не быть использованными второй раз.

-3

Ссылка на онлайн-компилятор языка C с текстом программы

Вся подборка задач:

Проект Эйлер | ZDG | Дзен