- •Элементарные алгоритмы для работы с графами
- •Работа алгоритма[править | править вики-текст]
- •Неформальное описание[править | править вики-текст]
- •Формальное описание[править | править вики-текст]
- •Алгоритм поиска в глубину[править | править вики-текст]
- •Нерекурсивные варианты[править | править вики-текст]
- •Общая идея
- •[Править]Пошаговое представление
- •[Править]Реализация
- •[Править]Время работы
- •[Править]Цвета вершин
- •Топологическая сортировка и сильно связные компоненты
- •↑ Пример ориентированного неотсортированного графа, к которому применима топологическая сортировка
- •Пример работы алгоритма[править | править вики-текст]
- •Алгоритмы[править | править вики-текст]
- •Минимальные остовные деревья (мst)
- •Введение
- •Постановка задачи
- •Кратчайшие пути
- •Давайте придумаем что-нибудь простое
- •А если я педант?
- •Задача о максимальном потоке
- •[Править]Определение потока
- •[Править]Пример
- •Увеличивающие пути. Теорема Бержа
- •Алгоритм Эдмондса. Сжатие цветков
- •Эффективная реализация
- •Оптимизация: предварительное построение паросочетания
- •Случай двудольного графа
- •Дальнейшая оптимизация
- •[Править]Реализация
- •[Править]Оценка производительности
- •[Править]Пример несходящегося алгоритма
- •[Править]Оценка быстродействия
- •[Править]Литература
- •Максимальные паросочетания[править | править вики-текст]
- •Описание алгоритма Необходимые определения
- •Теорема Бержа
- •Алгоритм Куна
- •Время работы
- •Реализация
- •Улучшенная реализация
- •[Править]Постановка задачи
- •[Править]Решение
- •[Править]Псевдокод
- •Префиксы и суффиксы строки
- •Прямые переходы
- •[Править]Суффиксные ссылки
- •Основные определения и описание структуры[править | править вики-текст]
- •Свойства суффиксных деревьев[править | править вики-текст]
- •Требования суффиксного дерева к памяти[править | править вики-текст]
- •[Править]Недостатки
- •Метод хеширования
- •[Править]Алгоритм
- •[Править]Псевдокод
- •[Править]Время работы
- •[Править]Надёжность
- •Автоматные модели в программировании
- •[Править]Переходы между состояниями [править]Прямые переходы
- •[Править]Суффиксные ссылки
- •[Править]Псевдокод
- •[Править]Пример использования
- •[Править]Псевдокод
- •[Править]Пример
- •[Править]Время работы
- •[Править]Эффективный алгоритм
- •[Править]Псевдокод
- •[Править]Время работы
- •[Править]Построение префикс-функции по z-функции [править]Постановка задачи
- •[Править]Описание алгоритма
- •Приближенные алгоритмы решения np-трудных задач
Неформальное описание[править | править вики-текст]
Поместить узел, с которого начинается поиск, в изначально пустую очередь.
Извлечь из начала очереди узел и пометить его как развёрнутый.
Если узел является целевым узлом, то завершить поиск с результатом «успех».
В противном случае, в конец очереди добавляются все преемники узла , которые ещё не развёрнуты и не находятся в очереди.
Если очередь пуста, то все узлы связного графа были просмотрены, следовательно, целевой узел недостижим из начального; завершить поиск с результатом «неудача».
Вернуться к п. 2.
Формальное описание[править | править вики-текст]
Ниже приведён псевдокод алгоритма для случая, когда необходимо лишь найти целевой узел. В зависимости от конкретного применения алгоритма, может потребоваться дополнительный код, обеспечивающий сохранение нужной информации (расстояние от начального узла, узел-родитель и т. п.)
Рекурсивная формулировка:
BFS(start_node, goal_node) {
return BFS'({start_node}, ∅, goal_node);
}
BFS'(fringe, visited, goal_node) {
if(fringe == ∅) {
// Целевой узел не найден
return false;
}
if (goal_node ∈ fringe) {
return true;
}
return BFS'({child | x ∈ fringe, child ∈ expand(x)} \ visited, visited ∪ fringe, goal_node);
}
Итеративная формулировка:
BFS(start_node, goal_node) {
for(all nodes i) visited[i] = false; // изначально список посещённых узлов пуст
queue.push(start_node); // начиная с узла-источника
visited[start_node] = true;
while(! queue.empty() ) { // пока очередь не пуста
node = queue.pop(); // извлечь первый элемент в очереди
if(node == goal_node) {
return true; // проверить, не является ли текущий узел целевым
}
foreach(child in expand(node)) { // все преемники текущего узла, ...
if(visited[child] == false) { // ... которые ещё не были посещены ...
queue.push(child); // ... добавить в конец очереди...
visited[child] = true; // ... и пометить как посещённые
}
}
}
return false; // Целевой узел недостижим
}
Свойства[править | править вики-текст]
Обозначим
число вершин и рёбер в графе
как
и
соответственно.
Пространственная сложность[править | править вики-текст]
Так
как в памяти хранятся все развёрнутые
узлы, пространственная
сложность алгоритма
составляет
[1].
Алгоритм поиска с итеративным углублением похож на поиск в ширину тем, что при каждой итерации перед переходом на следующий уровень исследуется полный уровень новых узлов, но требует значительно меньше памяти.
Временная сложность[править | править вики-текст]
Так как в худшем случае алгоритм посещает все узлы графа, при хранении графа в виде списков смежности, временная сложность алгоритма составляет [1][2].
Полнота[править | править вики-текст]
Если у каждого узла имеется конечное число преемников, алгоритм является полным: если решение существует, алгоритм поиска в ширину его находит, независимо от того, является ли граф конечным. Однако если решения не существует, на бесконечном графе поиск не завершается.
Оптимальность[править | править вики-текст]
Если длины рёбер графа равны между собой, поиск в ширину является оптимальным, то есть всегда находит кратчайший путь. В случае взвешенного графа поиск в ширину находит путь, содержащий минимальное количество рёбер, но не обязательно кратчайший.
Поиск по критерию стоимости является обобщением поиска в ширину и оптимален на взвешенном графе с неотрицательными весами рёбер. Алгоритм посещает узлы графа в порядке возрастания стоимости пути из начального узла и обычно использует очередь с приоритетами.
Поиск в глубину (алгоритм, классификация ребер, поиск циклов, время работы)
