fix Ru translation (#1894)

* 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
This commit is contained in:
Yudong Jin
2026-04-14 18:10:12 +08:00
committed by GitHub
parent 1d12e2def5
commit 22b3b568ef
94 changed files with 565 additions and 570 deletions
@@ -2,13 +2,13 @@
<u>Алгоритм поиска с возвратом (backtracking algorithm)</u> - это метод решения задач путем полного перебора. Его основная идея состоит в том, чтобы, начиная с некоторого исходного состояния, грубо перебрать все возможные решения, записывать корректные решения и продолжать поиск до тех пор, пока решение не будет найдено или пока не будут исчерпаны все возможные варианты.
Обычно алгоритмы поиска с возвратом используют обход в глубину для обхода пространства решений. В главе "Бинарные деревья" мы уже упоминали, что прямой, симметричный и обратный обходы относятся к обходу в глубину. Теперь мы на основе прямого обхода построим задачу поиска с возвратом и постепенно разберем принцип работы этого алгоритма.
Обычно алгоритмы поиска с возвратом используют обход в глубину для обхода пространства решений. В главе «Бинарные деревья» мы уже упоминали, что прямой, симметричный и обратный обходы относятся к обходу в глубину. Теперь мы на основе прямого обхода построим задачу поиска с возвратом и постепенно разберем принцип работы этого алгоритма.
!!! question "Пример 1"
Дано двоичное дерево. Найдите и запишите все узлы со значением $7$ ; верните список этих узлов.
Дано двоичное дерево. Найдите и запишите все узлы со значением $7$. Верните список этих узлов.
Для этой задачи мы выполняем прямой обход дерева и проверяем, равно ли значение текущего узла $7$ ; если да, то добавляем значение этого узла в список результатов `res` . Соответствующий процесс показан на рисунке ниже и в коде:
Для этой задачи мы выполняем прямой обход дерева и проверяем, равно ли значение текущего узла $7$. Если да, то добавляем значение этого узла в список результатов `res` . Соответствующий процесс показан на рисунке ниже и в коде:
```src
[file]{preorder_traversal_i_compact}-[class]{}-[func]{pre_order}
@@ -18,9 +18,9 @@
## Попытка и откат
**Алгоритм называется поиском с возвратом, потому что при поиске в пространстве решений он использует стратегию "попытка" и "откат"**. Когда в процессе поиска алгоритм приходит в состояние, из которого нельзя двигаться дальше или нельзя получить удовлетворяющее условиям решение, он отменяет предыдущий выбор, возвращается к более раннему состоянию и пробует другие возможные варианты.
**Алгоритм называется поиском с возвратом, потому что при поиске в пространстве решений он использует стратегию «попытка» и «откат»**. Когда в процессе поиска алгоритм приходит в состояние, из которого нельзя двигаться дальше или нельзя получить удовлетворяющее условиям решение, он отменяет предыдущий выбор, возвращается к более раннему состоянию и пробует другие возможные варианты.
Для примера 1 посещение каждого узла представляет собой "попытку", а прохождение листового узла или возврат к родителю через `return` означает "откат".
Для примера 1 посещение каждого узла представляет собой «попытку», а прохождение листового узла или возврат к родителю через `return` означает «откат».
Важно понимать, что **откат не сводится только к возврату из функции**. Чтобы показать это, слегка расширим пример 1.
@@ -34,9 +34,9 @@
[file]{preorder_traversal_ii_compact}-[class]{}-[func]{pre_order}
```
В каждой "попытке" мы добавляем текущий узел в `path` , чтобы записать путь; а перед "откатом" нам нужно удалить этот узел из `path` , **чтобы восстановить состояние, существовавшее до текущей попытки**.
В каждой «попытке» мы добавляем текущий узел в `path` , чтобы записать путь. А перед «откатом» нам нужно удалить этот узел из `path` , **чтобы восстановить состояние, существовавшее до текущей попытки**.
Если посмотреть на процесс, изображенный на рисунке ниже, **то попытку и откат можно понимать как "движение вперед" и "отмену"**: это два взаимно противоположных действия.
Если посмотреть на процесс, изображенный на рисунке ниже, **то попытку и откат можно понимать как «движение вперед» и «отмену»**: это два взаимно противоположных действия.
=== "<1>"
![Попытка и откат](backtracking_algorithm.assets/preorder_find_paths_step1.png)
@@ -73,7 +73,7 @@
## Обрезка
Сложные задачи поиска с возвратом обычно содержат одно или несколько ограничений, **которые часто можно использовать для "обрезки"**.
Сложные задачи поиска с возвратом обычно содержат одно или несколько ограничений, **которые часто можно использовать для «обрезки»**.
!!! question "Пример 3"
@@ -85,13 +85,13 @@
[file]{preorder_traversal_iii_compact}-[class]{}-[func]{pre_order}
```
Термин "обрезка" очень нагляден. Как показано на рисунке ниже, во время поиска **мы отсекаем ветви, не удовлетворяющие ограничениям** , тем самым избегая множества бессмысленных попыток и повышая эффективность поиска.
Термин «обрезка» очень нагляден. Как показано на рисунке ниже, во время поиска **мы отсекаем ветви, не удовлетворяющие ограничениям** , тем самым избегая множества бессмысленных попыток и повышая эффективность поиска.
![Обрезка по условиям задачи](backtracking_algorithm.assets/preorder_find_constrained_paths.png)
## Каркас кода
Теперь попробуем извлечь общий каркас из действий "попытка", "откат" и "обрезка", чтобы сделать код более универсальным.
Теперь попробуем извлечь общий каркас из действий «попытка», «откат» и «обрезка», чтобы сделать код более универсальным.
В следующем каркасе кода `state` обозначает текущее состояние задачи, а `choices` - список выборов, доступных в текущем состоянии:
@@ -449,7 +449,7 @@
| Термин | Определение | Пример 3 |
| ------------------------ | -------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| Решение (solution) | Решение - это ответ, удовлетворяющий условиям задачи; решений может быть одно или несколько | Все пути от корня до узла $7$ , удовлетворяющие ограничениям |
| Решение (solution) | Решение - это ответ, удовлетворяющий условиям задачи. Решений может быть одно или несколько | Все пути от корня до узла $7$ , удовлетворяющие ограничениям |
| Ограничение (constraint) | Ограничение определяет допустимость решения и обычно используется для обрезки | Путь не содержит узлы со значением $3$ |
| Состояние (state) | Состояние описывает ситуацию задачи в некоторый момент времени, включая уже сделанные выборы | Текущий путь посещенных узлов, то есть список узлов `path` |
| Попытка (attempt) | Попытка - это исследование пространства решений на основе доступных выборов, включая выбор, обновление состояния и проверку, является ли состояние решением | Рекурсивный переход к левому или правому потомку, добавление узла в `path` и проверка, равно ли значение узла $7$ |
@@ -458,7 +458,7 @@
!!! tip
Такие понятия, как задача, решение и состояние, являются общими и встречаются не только в поиске с возвратом, но и в "разделяй и властвуй", динамическом программировании, жадных алгоритмах и других темах.
Такие понятия, как задача, решение и состояние, являются общими и встречаются не только в поиске с возвратом, но и в «разделяй и властвуй», динамическом программировании, жадных алгоритмах и других темах.
## Преимущества и ограничения
@@ -481,23 +481,23 @@
**Поисковые задачи**: целью таких задач является поиск решений, удовлетворяющих определенным условиям.
- Задача о перестановках: дано множество, требуется найти все возможные перестановки его элементов.
- Задача о сумме подмножеств: даны множество и целевая сумма; нужно найти все подмножества, сумма элементов которых равна целевой.
- Задача о Ханойской башне: даны три стержня и набор дисков разного размера; требуется перенести все диски с одного стержня на другой, перемещая за раз только один диск и не помещая больший диск на меньший.
- Задача о сумме подмножеств: даны множество и целевая сумма. Нужно найти все подмножества, сумма элементов которых равна целевой.
- Задача о Ханойской башне: даны три стержня и набор дисков разного размера. Требуется перенести все диски с одного стержня на другой, перемещая за раз только один диск и не помещая больший диск на меньший.
**Задачи удовлетворения ограничений**: целью таких задач является поиск решений, удовлетворяющих всем ограничениям.
- Задача о $n$ ферзях: разместить $n$ ферзей на шахматной доске размера $n \times n$ так, чтобы они не атаковали друг друга.
- Судоку: заполнить сетку $9 \times 9$ числами от $1$ до $9$ так, чтобы в каждой строке, каждом столбце и каждом блоке $3 \times 3$ числа не повторялись.
- Задача раскраски графа: дан неориентированный граф; требуется раскрасить его вершины минимальным числом цветов так, чтобы соседние вершины имели разные цвета.
- Задача раскраски графа: дан неориентированный граф. Требуется раскрасить его вершины минимальным числом цветов так, чтобы соседние вершины имели разные цвета.
**Задачи комбинаторной оптимизации**: целью таких задач является поиск оптимального решения в некотором комбинаторном пространстве при заданных ограничениях.
- Задача о рюкзаке 0-1: даны набор предметов и рюкзак; у каждого предмета есть ценность и вес, и нужно выбрать предметы так, чтобы при ограниченной вместимости рюкзака суммарная ценность была максимальной.
- Задача о рюкзаке 0-1: даны набор предметов и рюкзак. У каждого предмета есть ценность и вес, и нужно выбрать предметы так, чтобы при ограниченной вместимости рюкзака суммарная ценность была максимальной.
- Задача коммивояжера: начиная из некоторой вершины графа, требуется посетить все остальные вершины ровно по одному разу и вернуться в исходную вершину, найдя при этом кратчайший путь.
- Задача о максимальной клике: дан неориентированный граф; требуется найти в нем максимальный полный подграф, то есть подграф, в котором любая пара вершин соединена ребром.
- Задача о максимальной клике: дан неориентированный граф. Требуется найти в нем максимальный полный подграф, то есть подграф, в котором любая пара вершин соединена ребром.
Стоит отметить: для многих задач комбинаторной оптимизации поиск с возвратом не является оптимальным способом решения.
- Задача о рюкзаке 0-1 обычно решается с помощью динамического программирования, что дает более высокую временную эффективность.
- Задача коммивояжера является известной NP-Hard задачей; для ее решения часто используют генетические алгоритмы, муравьиные алгоритмы и другие методы.
- Задача коммивояжера является известной NP-Hard задачей. Для ее решения часто используют генетические алгоритмы, муравьиные алгоритмы и другие методы.
- Задача о максимальной клике является классической задачей теории графов и может решаться жадными и другими эвристическими алгоритмами.