Есть число S. Сколькими способами можно набрать эт...
تم الإنشاء في: ٢٦ فبراير ٢٠٢٥
تم الإنشاء في: ٢٦ فبراير ٢٠٢٥
Есть число S. Сколькими способами можно набрать эту сумму монетами в 1, 2 и 5 рублей?
Ниже разберём классическую задачу о количестве способов набрать сумму с помощью монет номиналов 1, 2 и 5 рублей (при этом порядок монет не имеет значения).
Ищем количество неотрицательных целочисленных решений уравнения
где
Так как , нужно перебрать все возможные значения (от 0 до ), а для каждого зафиксированного посмотреть, сколькими способами можно добрать остаток монетами в 1 и 2 рубля.
Если мы обозначим , то количество решений для
равно .
Почему так? Потому что:
Итого, полное число способов набрать сумму монетами 1, 2 и 5 рублей (без учёта порядка) даёт сумма:
Другими словами, мы перебираем . Для каждого считаем, сколько есть способов составить монетами 1 и 2 рубля, и складываем результаты.
Ещё один популярный способ — метод динамического программирования. Пусть обозначает количество способов набрать сумму монетами (при этом порядок не важен). Тогда:
После обработки всех трёх номиналов в окажется количество искомых способов.
Ниже приведён условный псевдокод:
textfunction countWays(S): dp = массив из (S+1) элементов, заполненный нулями dp[0] = 1 # База: 1 способ набрать 0 coins = [1, 2, 5] for coin in coins: for n in range(coin, S+1): dp[n] += dp[n - coin] return dp[S]
После выполнения этого алгоритма dp[S]
вернёт то же самое число, что и формула выше, но часто такой код проще прямо реализовать в программе.
Для иллюстрации возьмём небольшую сумму, скажем, :
Через формулу
Нужно перебрать и , потому что .
Итого: способов.
Через динамику
dp[0] = 1
, остальные dp[1..6] = 0
.dp[1] += dp[0]
→ dp[1] = 1
dp[2] += dp[1]
→ dp[2] = 1
dp[3] += dp[2]
→ dp[3] = 1
dp[4] += dp[3]
→ dp[4] = 1
dp[5] += dp[4]
→ dp[5] = 1
dp[6] += dp[5]
→ dp[6] = 1
dp = [1,1,1,1,1,1,1]
.n
от 2 до 6:
dp[2] += dp[0]
→ dp[2] = 2
(т.е. 2 способа набрать 2: (1+1) или (2))dp[3] += dp[1]
→ dp[3] = 2
dp[4] += dp[2]
→ dp[4] = 1 + 2 = 3
dp[5] += dp[3]
→ dp[5] = 1 + 2 = 3
dp[6] += dp[4]
→ dp[6] = 1 + 3 = 4
n
от 5 до 6:
dp[5] += dp[0]
→ dp[5] = 3 + 1 = 4
dp[6] += dp[1]
→ dp[6] = 4 + 1 = 5
В итоге dp[6] = 5
.
Таким образом, оба подхода дают ответ .
Чтобы найти, сколькими способами можно набрать сумму монетами в 1, 2 и 5 рублей (без учёта порядка), можно использовать:
Явную суммирующую формулу:
Динамическое программирование, перебирая номиналы и заполняя массив , где — количество способов получить .
В конце в dp[S]
будет искомое число.
Оба способа эквивалентны по результату; выбор метода зависит от того, удобнее ли вам «быстрая» формула суммирования или универсальный программный подход.
Есть число S. Сколькими способами можно набрать эту сумму монетами в 1, 2 и 5 рублей?
Через python
Ниже приведён пример кода на Python, который вычисляет количество способов (без учёта порядка) набрать сумму S
монетами номиналов 1, 2 и 5 рублей с помощью динамического программирования:
pythondef count_ways(S): # dp[n] будет хранить количество способов набрать сумму n dp = [0] * (S + 1) # Для суммы 0 есть ровно 1 способ (не использовать монеты) dp[0] = 1 # Последовательно "добавляем" каждый из доступных номиналов for coin in [1, 2, 5]: for n in range(coin, S + 1): dp[n] += dp[n - coin] return dp[S] # Пример использования if __name__ == "__main__": S = 10 print(f"Количество способов набрать {S} рублей: {count_ways(S)}")
Как это работает:
dp
длиной S + 1
, где каждый элемент изначально равен 0.dp[0] = 1
, поскольку единственный способ набрать сумму 0 — не брать ни одной монеты.1, 2, 5
).S
. Для каждой суммы n
, мы обновляем dp[n]
, прибавляя к нему число способов набрать n - coin
.В итоге, когда перебраны все монеты, в dp[S]
будет записано количество уникальных комбинаций (без учёта порядка монет), дающих итоговую сумму S
.