mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-13 15:56:05 +00:00
build
This commit is contained in:
@@ -0,0 +1,451 @@
|
||||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
# 15.3 Задача о максимальной вместимости
|
||||
|
||||
!!! question
|
||||
|
||||
Дан массив $ht$, где каждый элемент обозначает высоту вертикальной перегородки. Любые две перегородки в массиве вместе с пространством между ними образуют контейнер.
|
||||
|
||||
Вместимость контейнера равна произведению высоты и ширины (площади), где высота определяется более короткой перегородкой, а ширина - разностью индексов двух перегородок в массиве.
|
||||
|
||||
Требуется выбрать две перегородки так, чтобы образованный ими контейнер имел максимальную вместимость. Пример показан на рисунке 15-7.
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Рисунок 15-7 Пример данных для задачи о максимальной вместимости </p>
|
||||
|
||||
Контейнер образуется произвольными двумя перегородками, **поэтому состоянием задачи служит пара индексов этих перегородок, обозначим ее как $[i, j]$**.
|
||||
|
||||
Согласно условию, вместимость равна произведению высоты на ширину, где высота определяется короткой перегородкой, а ширина - разностью индексов двух перегородок. Обозначим вместимость через $cap[i, j]$, тогда формула принимает вид:
|
||||
|
||||
$$
|
||||
cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
|
||||
$$
|
||||
|
||||
Пусть длина массива равна $n$. Тогда число пар перегородок, то есть общее число состояний, равно $C_n^2 = \frac{n(n - 1)}{2}$. Самый прямолинейный подход - **перебрать все состояния**, после чего найти максимальную вместимость. Его временная сложность равна $O(n^2)$.
|
||||
|
||||
### 1. Определение жадной стратегии
|
||||
|
||||
У этой задачи есть и более эффективное решение. Как показано на рисунке 15-8, рассмотрим состояние $[i, j]$, где индексы удовлетворяют $i < j$, а высоты - условию $ht[i] < ht[j]$, то есть $i$ - короткая перегородка, а $j$ - длинная.
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Рисунок 15-8 Начальное состояние </p>
|
||||
|
||||
Как показано на рисунке 15-9, **если в этот момент сдвинуть длинную перегородку $j$ ближе к короткой перегородке $i$, то вместимость обязательно уменьшится**.
|
||||
|
||||
Причина в том, что после смещения длинной перегородки $j$ ширина $j-i$ обязательно станет меньше, а высота определяется короткой перегородкой, поэтому высота либо останется прежней (если $i$ останется короткой перегородкой), либо уменьшится (если сдвинутая $j$ станет короткой перегородкой).
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Рисунок 15-9 Состояние после перемещения длинной перегородки внутрь </p>
|
||||
|
||||
Рассуждая в обратную сторону, **только сдвигая короткую перегородку $i$ внутрь, мы можем получить шанс увеличить вместимость**. Хотя ширина при этом обязательно уменьшится, **высота может возрасти** (если после перемещения короткая перегородка $i$ станет выше). Например, на рисунке 15-10 после перемещения короткой перегородки площадь увеличивается.
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Рисунок 15-10 Состояние после перемещения короткой перегородки внутрь </p>
|
||||
|
||||
Отсюда и выводится жадная стратегия для этой задачи: инициализировать два указателя по краям контейнера и на каждом шаге сдвигать внутрь указатель, соответствующий короткой перегородке, пока указатели не встретятся.
|
||||
|
||||
На рисунках ниже показан процесс выполнения этой жадной стратегии.
|
||||
|
||||
1. В начальном состоянии указатели $i$ и $j$ стоят на двух концах массива.
|
||||
2. Вычислить вместимость текущего состояния $cap[i, j]$ и обновить максимальную вместимость.
|
||||
3. Сравнить высоты перегородок $i$ и $j$, после чего сдвинуть короткую перегородку на одну позицию внутрь.
|
||||
4. Повторять шаги `2.` и `3.` до тех пор, пока $i$ и $j$ не встретятся.
|
||||
|
||||
=== "<1>"
|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<2>"
|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<3>"
|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<4>"
|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<5>"
|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<6>"
|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<7>"
|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<8>"
|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<9>"
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Рисунок 15-11 Жадный процесс решения задачи о максимальной вместимости </p>
|
||||
|
||||
### 2. Код реализации
|
||||
|
||||
Цикл в коде выполняется не более $n$ раз, **поэтому временная сложность равна $O(n)$**.
|
||||
|
||||
Переменные $i$, $j$, $res$ используют дополнительную память постоянного размера, **поэтому пространственная сложность равна $O(1)$**.
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python title="max_capacity.py"
|
||||
def max_capacity(ht: list[int]) -> int:
|
||||
"""Максимальная вместимость: жадный алгоритм"""
|
||||
# Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
i, j = 0, len(ht) - 1
|
||||
# Начальная максимальная вместимость равна 0
|
||||
res = 0
|
||||
# Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while i < j:
|
||||
# Обновить максимальную вместимость
|
||||
cap = min(ht[i], ht[j]) * (j - i)
|
||||
res = max(res, cap)
|
||||
# Сдвигать внутрь более короткую сторону
|
||||
if ht[i] < ht[j]:
|
||||
i += 1
|
||||
else:
|
||||
j -= 1
|
||||
return res
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp title="max_capacity.cpp"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
int maxCapacity(vector<int> &ht) {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
int i = 0, j = ht.size() - 1;
|
||||
// Начальная максимальная вместимость равна 0
|
||||
int res = 0;
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while (i < j) {
|
||||
// Обновить максимальную вместимость
|
||||
int cap = min(ht[i], ht[j]) * (j - i);
|
||||
res = max(res, cap);
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if (ht[i] < ht[j]) {
|
||||
i++;
|
||||
} else {
|
||||
j--;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java title="max_capacity.java"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
int maxCapacity(int[] ht) {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
int i = 0, j = ht.length - 1;
|
||||
// Начальная максимальная вместимость равна 0
|
||||
int res = 0;
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while (i < j) {
|
||||
// Обновить максимальную вместимость
|
||||
int cap = Math.min(ht[i], ht[j]) * (j - i);
|
||||
res = Math.max(res, cap);
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if (ht[i] < ht[j]) {
|
||||
i++;
|
||||
} else {
|
||||
j--;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="max_capacity.cs"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
int MaxCapacity(int[] ht) {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
int i = 0, j = ht.Length - 1;
|
||||
// Начальная максимальная вместимость равна 0
|
||||
int res = 0;
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while (i < j) {
|
||||
// Обновить максимальную вместимость
|
||||
int cap = Math.Min(ht[i], ht[j]) * (j - i);
|
||||
res = Math.Max(res, cap);
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if (ht[i] < ht[j]) {
|
||||
i++;
|
||||
} else {
|
||||
j--;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
|
||||
```go title="max_capacity.go"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
func maxCapacity(ht []int) int {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
i, j := 0, len(ht)-1
|
||||
// Начальная максимальная вместимость равна 0
|
||||
res := 0
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
for i < j {
|
||||
// Обновить максимальную вместимость
|
||||
capacity := int(math.Min(float64(ht[i]), float64(ht[j]))) * (j - i)
|
||||
res = int(math.Max(float64(res), float64(capacity)))
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if ht[i] < ht[j] {
|
||||
i++
|
||||
} else {
|
||||
j--
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="max_capacity.swift"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
func maxCapacity(ht: [Int]) -> Int {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
var i = ht.startIndex, j = ht.endIndex - 1
|
||||
// Начальная максимальная вместимость равна 0
|
||||
var res = 0
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while i < j {
|
||||
// Обновить максимальную вместимость
|
||||
let cap = min(ht[i], ht[j]) * (j - i)
|
||||
res = max(res, cap)
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if ht[i] < ht[j] {
|
||||
i += 1
|
||||
} else {
|
||||
j -= 1
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="max_capacity.js"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
function maxCapacity(ht) {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
let i = 0,
|
||||
j = ht.length - 1;
|
||||
// Начальная максимальная вместимость равна 0
|
||||
let res = 0;
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while (i < j) {
|
||||
// Обновить максимальную вместимость
|
||||
const cap = Math.min(ht[i], ht[j]) * (j - i);
|
||||
res = Math.max(res, cap);
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if (ht[i] < ht[j]) {
|
||||
i += 1;
|
||||
} else {
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
=== "TS"
|
||||
|
||||
```typescript title="max_capacity.ts"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
function maxCapacity(ht: number[]): number {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
let i = 0,
|
||||
j = ht.length - 1;
|
||||
// Начальная максимальная вместимость равна 0
|
||||
let res = 0;
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while (i < j) {
|
||||
// Обновить максимальную вместимость
|
||||
const cap: number = Math.min(ht[i], ht[j]) * (j - i);
|
||||
res = Math.max(res, cap);
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if (ht[i] < ht[j]) {
|
||||
i += 1;
|
||||
} else {
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="max_capacity.dart"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
int maxCapacity(List<int> ht) {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
int i = 0, j = ht.length - 1;
|
||||
// Начальная максимальная вместимость равна 0
|
||||
int res = 0;
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while (i < j) {
|
||||
// Обновить максимальную вместимость
|
||||
int cap = min(ht[i], ht[j]) * (j - i);
|
||||
res = max(res, cap);
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if (ht[i] < ht[j]) {
|
||||
i++;
|
||||
} else {
|
||||
j--;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="max_capacity.rs"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
fn max_capacity(ht: &[i32]) -> i32 {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
let mut i = 0;
|
||||
let mut j = ht.len() - 1;
|
||||
// Начальная максимальная вместимость равна 0
|
||||
let mut res = 0;
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while i < j {
|
||||
// Обновить максимальную вместимость
|
||||
let cap = std::cmp::min(ht[i], ht[j]) * (j - i) as i32;
|
||||
res = std::cmp::max(res, cap);
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if ht[i] < ht[j] {
|
||||
i += 1;
|
||||
} else {
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="max_capacity.c"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
int maxCapacity(int ht[], int htLength) {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
int i = 0;
|
||||
int j = htLength - 1;
|
||||
// Начальная максимальная вместимость равна 0
|
||||
int res = 0;
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while (i < j) {
|
||||
// Обновить максимальную вместимость
|
||||
int capacity = myMin(ht[i], ht[j]) * (j - i);
|
||||
res = myMax(res, capacity);
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if (ht[i] < ht[j]) {
|
||||
i++;
|
||||
} else {
|
||||
j--;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Kotlin"
|
||||
|
||||
```kotlin title="max_capacity.kt"
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
fun maxCapacity(ht: IntArray): Int {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
var i = 0
|
||||
var j = ht.size - 1
|
||||
// Начальная максимальная вместимость равна 0
|
||||
var res = 0
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while (i < j) {
|
||||
// Обновить максимальную вместимость
|
||||
val cap = min(ht[i], ht[j]) * (j - i)
|
||||
res = max(res, cap)
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
if (ht[i] < ht[j]) {
|
||||
i++
|
||||
} else {
|
||||
j--
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="max_capacity.rb"
|
||||
=begin
|
||||
File: max_capacity.rb
|
||||
Created Time: 2024-05-07
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
# ## Максимальная вместимость: жадный алгоритм ###
|
||||
def max_capacity(ht)
|
||||
# Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
i, j = 0, ht.length - 1
|
||||
# Начальная максимальная вместимость равна 0
|
||||
res = 0
|
||||
|
||||
# Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while i < j
|
||||
# Обновить максимальную вместимость
|
||||
cap = [ht[i], ht[j]].min * (j - i)
|
||||
res = [res, cap].max
|
||||
# Сдвигать внутрь более короткую сторону
|
||||
if ht[i] < ht[j]
|
||||
i += 1
|
||||
else
|
||||
j -= 1
|
||||
end
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
```
|
||||
|
||||
??? pythontutor "Визуализация кода"
|
||||
|
||||
<div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20max_capacity%28ht%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%D0%9C%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F%20%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C%3A%20%D0%B6%D0%B0%D0%B4%D0%BD%D1%8B%D0%B9%20%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%22%22%22%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20i%20%D0%B8%20j%20%D1%82%D0%B0%D0%BA%2C%20%D1%87%D1%82%D0%BE%D0%B1%D1%8B%20%D0%BE%D0%BD%D0%B8%20%D1%80%D0%B0%D1%81%D0%BF%D0%BE%D0%BB%D0%B0%D0%B3%D0%B0%D0%BB%D0%B8%D1%81%D1%8C%20%D0%BF%D0%BE%20%D0%B4%D0%B2%D1%83%D0%BC%20%D0%BA%D0%BE%D0%BD%D1%86%D0%B0%D0%BC%20%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28ht%29%20-%201%0A%20%20%20%20%23%20%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F%20%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F%20%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C%20%D1%80%D0%B0%D0%B2%D0%BD%D0%B0%200%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20%23%20%D0%92%D1%8B%D0%BF%D0%BE%D0%BB%D0%BD%D1%8F%D1%82%D1%8C%20%D0%B6%D0%B0%D0%B4%D0%BD%D1%8B%D0%B9%20%D0%B2%D1%8B%D0%B1%D0%BE%D1%80%20%D0%B2%20%D1%86%D0%B8%D0%BA%D0%BB%D0%B5%2C%20%D0%BF%D0%BE%D0%BA%D0%B0%20%D0%B4%D0%B2%D0%B5%20%D0%B4%D0%BE%D1%81%D0%BA%D0%B8%20%D0%BD%D0%B5%20%D0%B2%D1%81%D1%82%D1%80%D0%B5%D1%82%D1%8F%D1%82%D1%81%D1%8F%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20%23%20%D0%9E%D0%B1%D0%BD%D0%BE%D0%B2%D0%B8%D1%82%D1%8C%20%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D1%83%D1%8E%20%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C%0A%20%20%20%20%20%20%20%20cap%20%3D%20min%28ht%5Bi%5D%2C%20ht%5Bj%5D%29%20%2A%20%28j%20-%20i%29%0A%20%20%20%20%20%20%20%20res%20%3D%20max%28res%2C%20cap%29%0A%20%20%20%20%20%20%20%20%23%20%D0%A1%D0%B4%D0%B2%D0%B8%D0%B3%D0%B0%D1%82%D1%8C%20%D0%B2%D0%BD%D1%83%D1%82%D1%80%D1%8C%20%D0%B1%D0%BE%D0%BB%D0%B5%D0%B5%20%D0%BA%D0%BE%D1%80%D0%BE%D1%82%D0%BA%D1%83%D1%8E%20%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D1%83%0A%20%20%20%20%20%20%20%20if%20ht%5Bi%5D%20%3C%20ht%5Bj%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20ht%20%3D%20%5B3%2C%208%2C%205%2C%202%2C%207%2C%207%2C%203%2C%204%5D%0A%0A%20%20%20%20%23%20%D0%96%D0%B0%D0%B4%D0%BD%D1%8B%D0%B9%20%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%0A%20%20%20%20res%20%3D%20max_capacity%28ht%29%0A%20%20%20%20print%28f%22%D0%9C%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F%20%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C%20%3D%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=4&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
|
||||
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20max_capacity%28ht%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%D0%9C%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F%20%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C%3A%20%D0%B6%D0%B0%D0%B4%D0%BD%D1%8B%D0%B9%20%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%22%22%22%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20i%20%D0%B8%20j%20%D1%82%D0%B0%D0%BA%2C%20%D1%87%D1%82%D0%BE%D0%B1%D1%8B%20%D0%BE%D0%BD%D0%B8%20%D1%80%D0%B0%D1%81%D0%BF%D0%BE%D0%BB%D0%B0%D0%B3%D0%B0%D0%BB%D0%B8%D1%81%D1%8C%20%D0%BF%D0%BE%20%D0%B4%D0%B2%D1%83%D0%BC%20%D0%BA%D0%BE%D0%BD%D1%86%D0%B0%D0%BC%20%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28ht%29%20-%201%0A%20%20%20%20%23%20%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F%20%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F%20%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C%20%D1%80%D0%B0%D0%B2%D0%BD%D0%B0%200%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20%23%20%D0%92%D1%8B%D0%BF%D0%BE%D0%BB%D0%BD%D1%8F%D1%82%D1%8C%20%D0%B6%D0%B0%D0%B4%D0%BD%D1%8B%D0%B9%20%D0%B2%D1%8B%D0%B1%D0%BE%D1%80%20%D0%B2%20%D1%86%D0%B8%D0%BA%D0%BB%D0%B5%2C%20%D0%BF%D0%BE%D0%BA%D0%B0%20%D0%B4%D0%B2%D0%B5%20%D0%B4%D0%BE%D1%81%D0%BA%D0%B8%20%D0%BD%D0%B5%20%D0%B2%D1%81%D1%82%D1%80%D0%B5%D1%82%D1%8F%D1%82%D1%81%D1%8F%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20%23%20%D0%9E%D0%B1%D0%BD%D0%BE%D0%B2%D0%B8%D1%82%D1%8C%20%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D1%83%D1%8E%20%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C%0A%20%20%20%20%20%20%20%20cap%20%3D%20min%28ht%5Bi%5D%2C%20ht%5Bj%5D%29%20%2A%20%28j%20-%20i%29%0A%20%20%20%20%20%20%20%20res%20%3D%20max%28res%2C%20cap%29%0A%20%20%20%20%20%20%20%20%23%20%D0%A1%D0%B4%D0%B2%D0%B8%D0%B3%D0%B0%D1%82%D1%8C%20%D0%B2%D0%BD%D1%83%D1%82%D1%80%D1%8C%20%D0%B1%D0%BE%D0%BB%D0%B5%D0%B5%20%D0%BA%D0%BE%D1%80%D0%BE%D1%82%D0%BA%D1%83%D1%8E%20%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D1%83%0A%20%20%20%20%20%20%20%20if%20ht%5Bi%5D%20%3C%20ht%5Bj%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20ht%20%3D%20%5B3%2C%208%2C%205%2C%202%2C%207%2C%207%2C%203%2C%204%5D%0A%0A%20%20%20%20%23%20%D0%96%D0%B0%D0%B4%D0%BD%D1%8B%D0%B9%20%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%0A%20%20%20%20res%20%3D%20max_capacity%28ht%29%0A%20%20%20%20print%28f%22%D0%9C%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F%20%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C%20%3D%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=4&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Во весь экран ></a></div>
|
||||
|
||||
### 3. Доказательство корректности
|
||||
|
||||
Жадный алгоритм быстрее полного перебора именно потому, что каждый жадный шаг «пропускает» часть состояний.
|
||||
|
||||
Например, в состоянии $cap[i, j]$ перегородка $i$ является короткой, а $j$ - длинной. Если жадно сдвинуть короткую перегородку $i$ на одну позицию внутрь, то состояния, показанные на рисунке 15-12, будут «пропущены». **Это означает, что позже мы уже не сможем проверить вместимость этих состояний**.
|
||||
|
||||
$$
|
||||
cap[i, i+1], cap[i, i+2], \dots, cap[i, j-2], cap[i, j-1]
|
||||
$$
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Рисунок 15-12 Состояния, пропущенные из-за смещения короткой перегородки </p>
|
||||
|
||||
Нетрудно заметить, что **эти пропущенные состояния на самом деле и есть все состояния, в которых длинная перегородка $j$ сдвигается внутрь**. Ранее мы уже доказали, что перемещение длинной перегородки внутрь обязательно уменьшает вместимость. Иными словами, пропущенные состояния не могут быть оптимальным решением, **поэтому их пропуск не приводит к потере оптимума**.
|
||||
|
||||
Приведенный анализ показывает, что операция перемещения короткой перегородки является «безопасной», а жадная стратегия действительно эффективна.
|
||||
Reference in New Issue
Block a user