mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-05 12:14:20 +00:00
deploy
This commit is contained in:
@@ -4623,7 +4623,7 @@
|
||||
<p align="center"> Рисунок 14-22 Пример данных для задачи о полном рюкзаке </p>
|
||||
|
||||
<h3 id="1">1. Идея динамического программирования<a class="headerlink" href="#1" title="Permanent link">¶</a></h3>
|
||||
<p>Задача о полном рюкзаке очень похожа на задачу о рюкзаке 0-1; <strong>разница состоит только в том, что количество выборов каждого предмета не ограничено</strong>.</p>
|
||||
<p>Задача о полном рюкзаке очень похожа на задачу о рюкзаке 0-1. <strong>Разница состоит только в том, что количество выборов каждого предмета не ограничено</strong>.</p>
|
||||
<ul>
|
||||
<li>В задаче о рюкзаке 0-1 каждого предмета существует только один экземпляр, поэтому после того как предмет <span class="arithmatex">\(i\)</span> помещен в рюкзак, выбирать можно только из первых <span class="arithmatex">\(i-1\)</span> предметов.</li>
|
||||
<li>В задаче о полном рюкзаке количество предметов не ограничено, поэтому после того как предмет <span class="arithmatex">\(i\)</span> помещен в рюкзак, <strong>можно продолжать выбирать из первых <span class="arithmatex">\(i\)</span> предметов</strong>.</li>
|
||||
@@ -4638,7 +4638,7 @@
|
||||
dp[i, c] = \max(dp[i-1, c], dp[i, c - wgt[i-1]] + val[i-1])
|
||||
\]</div>
|
||||
<h3 id="2">2. Реализация кода<a class="headerlink" href="#2" title="Permanent link">¶</a></h3>
|
||||
<p>Если сравнить код этой задачи с кодом задачи о рюкзаке 0-1, то окажется, что в переходе состояний меняется только одна деталь: вместо <span class="arithmatex">\(i-1\)</span> появляется <span class="arithmatex">\(i\)</span> ; все остальное остается таким же:</p>
|
||||
<p>Если сравнить код этой задачи с кодом задачи о рюкзаке 0-1, то окажется, что в переходе состояний меняется только одна деталь: вместо <span class="arithmatex">\(i-1\)</span> появляется <span class="arithmatex">\(i\)</span>. Все остальное остается таким же:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="1:13"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><input id="__tabbed_1_8" name="__tabbed_1" type="radio" /><input id="__tabbed_1_9" name="__tabbed_1" type="radio" /><input id="__tabbed_1_10" name="__tabbed_1" type="radio" /><input id="__tabbed_1_11" name="__tabbed_1" type="radio" /><input id="__tabbed_1_12" name="__tabbed_1" type="radio" /><input id="__tabbed_1_13" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Python</label><label for="__tabbed_1_2">C++</label><label for="__tabbed_1_3">Java</label><label for="__tabbed_1_4">C#</label><label for="__tabbed_1_5">Go</label><label for="__tabbed_1_6">Swift</label><label for="__tabbed_1_7">JS</label><label for="__tabbed_1_8">TS</label><label for="__tabbed_1_9">Dart</label><label for="__tabbed_1_10">Rust</label><label for="__tabbed_1_11">C</label><label for="__tabbed_1_12">Kotlin</label><label for="__tabbed_1_13">Ruby</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -4957,7 +4957,7 @@ dp[i, c] = \max(dp[i-1, c], dp[i, c - wgt[i-1]] + val[i-1])
|
||||
</details>
|
||||
<h3 id="3">3. Оптимизация пространства<a class="headerlink" href="#3" title="Permanent link">¶</a></h3>
|
||||
<p>Поскольку текущее состояние переходит из состояния слева и состояния сверху, <strong>после оптимизации памяти каждую строку таблицы <span class="arithmatex">\(dp\)</span> нужно обходить слева направо</strong>.</p>
|
||||
<p>Этот порядок обхода как раз противоположен задаче о рюкзаке 0-1. Разницу удобно понять по рисунку ниже.</p>
|
||||
<p>Этот порядок обхода как раз противоположен задаче о рюкзаке 0-1. Эту разницу удобно понять, рассмотрев то, что показано на рисунке 14-23.</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="2:6"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><input id="__tabbed_2_4" name="__tabbed_2" type="radio" /><input id="__tabbed_2_5" name="__tabbed_2" type="radio" /><input id="__tabbed_2_6" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1"><1></label><label for="__tabbed_2_2"><2></label><label for="__tabbed_2_3"><3></label><label for="__tabbed_2_4"><4></label><label for="__tabbed_2_5"><5></label><label for="__tabbed_2_6"><6></label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -5317,9 +5317,9 @@ dp[i, c] = \max(dp[i-1, c], dp[i, c - wgt[i-1]] + val[i-1])
|
||||
<p align="center"> Рисунок 14-24 Пример данных для задачи о размене монет </p>
|
||||
|
||||
<h3 id="1_1">1. Идея динамического программирования<a class="headerlink" href="#1_1" title="Permanent link">¶</a></h3>
|
||||
<p><strong>Задачу о размене монет можно рассматривать как частный случай задачи о полном рюкзаке</strong> ; между ними существуют следующие соответствия и различия.</p>
|
||||
<p><strong>Задачу о размене монет можно рассматривать как частный случай задачи о полном рюкзаке</strong>. Между ними существуют следующие соответствия и различия.</p>
|
||||
<ul>
|
||||
<li>Эти две задачи можно взаимно преобразовать: "предмет" соответствует "монете", "вес предмета" соответствует "номиналу монеты", а "вместимость рюкзака" соответствует "целевой сумме".</li>
|
||||
<li>Эти две задачи можно взаимно преобразовать: «предмет» соответствует «монете», «вес предмета» соответствует «номиналу монеты», а «вместимость рюкзака» соответствует «целевой сумме».</li>
|
||||
<li>Цель оптимизации противоположна: в задаче о полном рюкзаке нужно максимизировать стоимость предметов, а в задаче о размене монет - минимизировать число монет.</li>
|
||||
<li>В задаче о полном рюкзаке ищется решение, не превышающее вместимость, а в задаче о размене монет требуется <strong>ровно</strong> набрать целевую сумму.</li>
|
||||
</ul>
|
||||
@@ -5337,10 +5337,10 @@ dp[i, a] = \min(dp[i-1, a], dp[i, a - coins[i-1]] + 1)
|
||||
\]</div>
|
||||
<p><strong>Шаг 3: определить граничные условия и порядок переходов</strong></p>
|
||||
<p>Когда целевая сумма равна <span class="arithmatex">\(0\)</span> , минимальное число монет для ее набора равно <span class="arithmatex">\(0\)</span> , то есть весь первый столбец <span class="arithmatex">\(dp[i, 0]\)</span> заполняется нулями.</p>
|
||||
<p>Когда монет нет, <strong>невозможно набрать никакую целевую сумму <span class="arithmatex">\(> 0\)</span></strong> ; это и есть недопустимое решение. Чтобы функция <span class="arithmatex">\(\min()\)</span> в уравнении перехода состояния могла распознавать и отбрасывать такие недопустимые решения, удобно использовать значение <span class="arithmatex">\(+ \infty\)</span> ; то есть всю первую строку <span class="arithmatex">\(dp[0, a]\)</span> нужно инициализировать значением <span class="arithmatex">\(+ \infty\)</span> .</p>
|
||||
<p>Когда монет нет, <strong>невозможно набрать никакую целевую сумму <span class="arithmatex">\(> 0\)</span></strong>. Это и есть недопустимое решение. Чтобы функция <span class="arithmatex">\(\min()\)</span> в уравнении перехода состояния могла распознавать и отбрасывать такие недопустимые решения, удобно использовать значение <span class="arithmatex">\(+ \infty\)</span>. То есть всю первую строку <span class="arithmatex">\(dp[0, a]\)</span> нужно инициализировать значением <span class="arithmatex">\(+ \infty\)</span> .</p>
|
||||
<h3 id="2_1">2. Реализация кода<a class="headerlink" href="#2_1" title="Permanent link">¶</a></h3>
|
||||
<p>Большинство языков программирования не предоставляет представление для <span class="arithmatex">\(+ \infty\)</span> в целочисленном виде, поэтому обычно приходится заменять его на максимальное значение типа <code>int</code> . Но тогда возникает риск переполнения: операция <span class="arithmatex">\(+ 1\)</span> в уравнении перехода может переполнить большое число.</p>
|
||||
<p>Поэтому здесь мы используем число <span class="arithmatex">\(amt + 1\)</span> как обозначение недопустимого решения, потому что для набора суммы <span class="arithmatex">\(amt\)</span> максимум нужно не больше чем <span class="arithmatex">\(amt\)</span> монет. Перед возвратом результата проверяем, равно ли <span class="arithmatex">\(dp[n, amt]\)</span> значению <span class="arithmatex">\(amt + 1\)</span> ; если да, то возвращаем <span class="arithmatex">\(-1\)</span> , что означает невозможность набрать целевую сумму. Код приведен ниже:</p>
|
||||
<p>Поэтому здесь мы используем число <span class="arithmatex">\(amt + 1\)</span> как обозначение недопустимого решения, потому что для набора суммы <span class="arithmatex">\(amt\)</span> максимум нужно не больше чем <span class="arithmatex">\(amt\)</span> монет. Перед возвратом результата проверяем, равно ли <span class="arithmatex">\(dp[n, amt]\)</span> значению <span class="arithmatex">\(amt + 1\)</span>. Если да, то возвращаем <span class="arithmatex">\(-1\)</span> , что означает невозможность набрать целевую сумму. Код приведен ниже:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="4:13"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><input id="__tabbed_4_3" name="__tabbed_4" type="radio" /><input id="__tabbed_4_4" name="__tabbed_4" type="radio" /><input id="__tabbed_4_5" name="__tabbed_4" type="radio" /><input id="__tabbed_4_6" name="__tabbed_4" type="radio" /><input id="__tabbed_4_7" name="__tabbed_4" type="radio" /><input id="__tabbed_4_8" name="__tabbed_4" type="radio" /><input id="__tabbed_4_9" name="__tabbed_4" type="radio" /><input id="__tabbed_4_10" name="__tabbed_4" type="radio" /><input id="__tabbed_4_11" name="__tabbed_4" type="radio" /><input id="__tabbed_4_12" name="__tabbed_4" type="radio" /><input id="__tabbed_4_13" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">Python</label><label for="__tabbed_4_2">C++</label><label for="__tabbed_4_3">Java</label><label for="__tabbed_4_4">C#</label><label for="__tabbed_4_5">Go</label><label for="__tabbed_4_6">Swift</label><label for="__tabbed_4_7">JS</label><label for="__tabbed_4_8">TS</label><label for="__tabbed_4_9">Dart</label><label for="__tabbed_4_10">Rust</label><label for="__tabbed_4_11">C</label><label for="__tabbed_4_12">Kotlin</label><label for="__tabbed_4_13">Ruby</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
|
||||
Reference in New Issue
Block a user