mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-05 12:14:20 +00:00
build
This commit is contained in:
@@ -18,7 +18,7 @@ comments: true
|
||||
|
||||
### 1. Идея динамического программирования
|
||||
|
||||
Задача о полном рюкзаке очень похожа на задачу о рюкзаке 0-1; **разница состоит только в том, что количество выборов каждого предмета не ограничено**.
|
||||
Задача о полном рюкзаке очень похожа на задачу о рюкзаке 0-1. **Разница состоит только в том, что количество выборов каждого предмета не ограничено**.
|
||||
|
||||
- В задаче о рюкзаке 0-1 каждого предмета существует только один экземпляр, поэтому после того как предмет $i$ помещен в рюкзак, выбирать можно только из первых $i-1$ предметов.
|
||||
- В задаче о полном рюкзаке количество предметов не ограничено, поэтому после того как предмет $i$ помещен в рюкзак, **можно продолжать выбирать из первых $i$ предметов**.
|
||||
@@ -36,7 +36,7 @@ $$
|
||||
|
||||
### 2. Реализация кода
|
||||
|
||||
Если сравнить код этой задачи с кодом задачи о рюкзаке 0-1, то окажется, что в переходе состояний меняется только одна деталь: вместо $i-1$ появляется $i$ ; все остальное остается таким же:
|
||||
Если сравнить код этой задачи с кодом задачи о рюкзаке 0-1, то окажется, что в переходе состояний меняется только одна деталь: вместо $i-1$ появляется $i$. Все остальное остается таким же:
|
||||
|
||||
=== "Python"
|
||||
|
||||
@@ -380,7 +380,7 @@ $$
|
||||
|
||||
Поскольку текущее состояние переходит из состояния слева и состояния сверху, **после оптимизации памяти каждую строку таблицы $dp$ нужно обходить слева направо**.
|
||||
|
||||
Этот порядок обхода как раз противоположен задаче о рюкзаке 0-1. Разницу удобно понять по рисунку ниже.
|
||||
Этот порядок обхода как раз противоположен задаче о рюкзаке 0-1. Эту разницу удобно понять, рассмотрев то, что показано на рисунке 14-23.
|
||||
|
||||
=== "<1>"
|
||||
{ class="animation-figure" }
|
||||
@@ -764,9 +764,9 @@ $$
|
||||
|
||||
### 1. Идея динамического программирования
|
||||
|
||||
**Задачу о размене монет можно рассматривать как частный случай задачи о полном рюкзаке** ; между ними существуют следующие соответствия и различия.
|
||||
**Задачу о размене монет можно рассматривать как частный случай задачи о полном рюкзаке**. Между ними существуют следующие соответствия и различия.
|
||||
|
||||
- Эти две задачи можно взаимно преобразовать: "предмет" соответствует "монете", "вес предмета" соответствует "номиналу монеты", а "вместимость рюкзака" соответствует "целевой сумме".
|
||||
- Эти две задачи можно взаимно преобразовать: «предмет» соответствует «монете», «вес предмета» соответствует «номиналу монеты», а «вместимость рюкзака» соответствует «целевой сумме».
|
||||
- Цель оптимизации противоположна: в задаче о полном рюкзаке нужно максимизировать стоимость предметов, а в задаче о размене монет - минимизировать число монет.
|
||||
- В задаче о полном рюкзаке ищется решение, не превышающее вместимость, а в задаче о размене монет требуется **ровно** набрать целевую сумму.
|
||||
|
||||
@@ -791,13 +791,13 @@ $$
|
||||
|
||||
Когда целевая сумма равна $0$ , минимальное число монет для ее набора равно $0$ , то есть весь первый столбец $dp[i, 0]$ заполняется нулями.
|
||||
|
||||
Когда монет нет, **невозможно набрать никакую целевую сумму $> 0$** ; это и есть недопустимое решение. Чтобы функция $\min()$ в уравнении перехода состояния могла распознавать и отбрасывать такие недопустимые решения, удобно использовать значение $+ \infty$ ; то есть всю первую строку $dp[0, a]$ нужно инициализировать значением $+ \infty$ .
|
||||
Когда монет нет, **невозможно набрать никакую целевую сумму $> 0$**. Это и есть недопустимое решение. Чтобы функция $\min()$ в уравнении перехода состояния могла распознавать и отбрасывать такие недопустимые решения, удобно использовать значение $+ \infty$. То есть всю первую строку $dp[0, a]$ нужно инициализировать значением $+ \infty$ .
|
||||
|
||||
### 2. Реализация кода
|
||||
|
||||
Большинство языков программирования не предоставляет представление для $+ \infty$ в целочисленном виде, поэтому обычно приходится заменять его на максимальное значение типа `int` . Но тогда возникает риск переполнения: операция $+ 1$ в уравнении перехода может переполнить большое число.
|
||||
|
||||
Поэтому здесь мы используем число $amt + 1$ как обозначение недопустимого решения, потому что для набора суммы $amt$ максимум нужно не больше чем $amt$ монет. Перед возвратом результата проверяем, равно ли $dp[n, amt]$ значению $amt + 1$ ; если да, то возвращаем $-1$ , что означает невозможность набрать целевую сумму. Код приведен ниже:
|
||||
Поэтому здесь мы используем число $amt + 1$ как обозначение недопустимого решения, потому что для набора суммы $amt$ максимум нужно не больше чем $amt$ монет. Перед возвратом результата проверяем, равно ли $dp[n, amt]$ значению $amt + 1$. Если да, то возвращаем $-1$ , что означает невозможность набрать целевую сумму. Код приведен ниже:
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user