mirror of
http://bgp.hk.skcks.cn:10086/https://github.com/krahets/hello-algo
synced 2026-04-20 21:00:58 +08:00
* docs(ru): replace prose quotes with guillemets * docs(ru): replace prose semicolons with periods * docs(ru): align animation title forms * docs(ru): align figure and table references
26 lines
8.0 KiB
Markdown
26 lines
8.0 KiB
Markdown
# Резюме
|
||
|
||
### Ключевые выводы
|
||
|
||
- Динамическое программирование раскладывает задачу на подзадачи и повышает вычислительную эффективность за счет хранения решений этих подзадач и устранения повторных вычислений.
|
||
- Если не учитывать затраты времени, то любую задачу динамического программирования можно решить с помощью поиска с возвратом (полного перебора), однако в дереве рекурсии возникает множество перекрывающихся подзадач, из-за чего эффективность крайне низка. После введения таблицы памяти можно хранить решения всех уже вычисленных подзадач и гарантировать, что каждая перекрывающаяся подзадача будет вычисляться только один раз.
|
||
- Поиск с мемоизацией - это рекурсивный метод «сверху вниз», а соответствующее ему динамическое программирование - это итеративный метод «снизу вверх», похожий на заполнение таблицы. Поскольку текущее состояние обычно зависит только от части локальных состояний, можно убрать одно измерение таблицы $dp$ и тем самым снизить пространственную сложность.
|
||
- Разложение на подзадачи - это общий алгоритмический подход, но в методе «разделяй и властвуй», динамическом программировании и поиске с возвратом он имеет разные свойства.
|
||
- Для задач динамического программирования характерны три главных свойства: перекрывающиеся подзадачи, оптимальная подструктура и отсутствие последствий.
|
||
- Если оптимальное решение исходной задачи можно построить из оптимальных решений подзадач, то задача обладает оптимальной подструктурой.
|
||
- Отсутствие последствий означает, что для данного состояния его дальнейшее развитие определяется только этим состоянием и не зависит от всех прошлых состояний. Многие задачи комбинаторной оптимизации этим свойством не обладают и потому не могут эффективно решаться с помощью динамического программирования.
|
||
|
||
**Задачи о рюкзаке**
|
||
|
||
- Задача о рюкзаке - один из самых типичных классов задач динамического программирования. Она включает варианты 0-1 рюкзака, полного рюкзака, многократного рюкзака и другие.
|
||
- В задаче о рюкзаке 0-1 состояние определяется как максимальная стоимость первых $i$ предметов в рюкзаке вместимости $c$ . Рассматривая два решения - не брать предмет и брать предмет, - можно получить оптимальную подструктуру и вывести уравнение перехода состояния. При оптимизации памяти, поскольку каждое состояние зависит от значения сверху и слева сверху, внутренний цикл нужно выполнять в обратном порядке, чтобы не перезаписать нужное значение.
|
||
- В задаче о полном рюкзаке число экземпляров каждого предмета не ограничено, поэтому при выборе предмета переход состояния отличается от варианта 0-1. Поскольку состояние зависит от значения сверху и слева, после оптимизации памяти внутренний цикл следует выполнять в прямом порядке.
|
||
- Задача о размене монет - это вариант задачи о полном рюкзаке. Здесь вместо «максимальной стоимости» ищется «минимальное число монет», поэтому в уравнении перехода $\max()$ заменяется на $\min()$ . Кроме того, вместо условия «не превышать вместимость рюкзака» нужно **ровно** набрать целевую сумму, поэтому значение $amt + 1$ используется как обозначение недопустимого решения «сумму набрать нельзя».
|
||
- В задаче о размене монет II вместо «минимального числа монет» требуется найти «число комбинаций монет», поэтому в уравнении перехода оператор $\min()$ заменяется на суммирование.
|
||
|
||
**Задача о расстоянии редактирования**
|
||
|
||
- Расстояние редактирования (расстояние Левенштейна) используется для измерения сходства двух строк и определяется как минимальное число операций редактирования, необходимых для преобразования одной строки в другую. Допустимые операции - вставка, удаление и замена.
|
||
- В задаче о расстоянии редактирования состояние определяется как минимальное число шагов редактирования, необходимых для преобразования первых $i$ символов строки $s$ в первые $j$ символов строки $t$ . Если $s[i] \ne t[j]$ , то существуют три решения: вставка, удаление и замена, и каждому из них соответствует своя остаточная подзадача. На этой основе выводятся оптимальная подструктура и уравнение перехода состояния. Если же $s[i] = t[j]$ , то редактировать текущий символ не нужно.
|
||
- В задаче о расстоянии редактирования состояние зависит от значений сверху, слева и слева сверху. Поэтому после оптимизации памяти ни прямой, ни обратный обход сам по себе не дает корректного перехода состояния. Для решения этой проблемы значение слева сверху временно сохраняется в отдельной переменной, что делает ситуацию эквивалентной задаче о полном рюкзаке и позволяет использовать прямой обход.
|