Рассмотрите задачу на графах: предложите критерии выбора между алгоритмом Дейкстры, Беллмана–Форда и алгоритмами для обхода (BFS/DFS) в прикладных задачах (карты, сети с отрицательными весами, топологическая сортировка), приведите доказательство корректности выбранного алгоритма для каждого случая и проанализируйте сложность
Кратко — какие критерии выбирать и почему, с доказательствами корректности и оценкой сложности.
1) Критерии выбора обобщённообобщённообобщённо
Если граф не взвешен всерёбраимеют«одинаковый»вес,либоинтересуетминимумчисларёбервсе рёбра имеют «одинаковый» вес, либо интересует минимум числа рёбервсерёбраимеют«одинаковый»вес,либоинтересуетминимумчисларёбер → BFS одинисточникодин источникодинисточник или многопроходный BFS несколькоисточниковнесколько источниковнесколькоисточников.Если взвешен, веса неотрицательные → Dijkstra быстрыйбыстрыйбыстрый.Если возможны отрицательные веса и нужно корректно обработать их и/илиобнаружитьотрицательныециклыи/или обнаружить отрицательные циклыи/илиобнаружитьотрицательныециклы → Bellman–Ford.Если нужно только проверка достижимости, обход всех вершин, компоненты связности, построение порядка при DAG → DFS илиBFSдлянекоторыхзадачили BFS для некоторых задачилиBFSдлянекоторыхзадач.Для топологической сортировки DAG → Kahn BFS−подобныйBFS-подобныйBFS−подобный или DFS поубываниювремениокончанияпо убыванию времени окончанияпоубываниювремениокончания.Если нужны кратчайшие пути между всеми парами вершин: для dense графа — Floyd–Warshall; для sparse с возможными отрицательными весами без негативных циклов — Johnson перевесить+Dijkstraперевесить + Dijkstraперевесить+Dijkstra.Практические соображения: для очень больших разреженных графов использовать Dijkstra с кучей heapheapheap; для плотных графов Dijkstra с матрицей/масивом может быть эффективнее O(V2)O(V^2)O(V2). Bellman–Ford обычно дороже O(VE)O(VE)O(VE), но прост в реализации и даёт обнаружение отрицательных циклов.
2) BFS обходвширинуобход в ширинуобходвширину. Применение
Невзвешенные графы: кратчайший путь по числу рёбер.Поиск достижимости, минимальное число шагов, многоточечные волны.
Доказательство корректности краткократкократко
BFS строит слои: расстояние distvvv = уровень, на котором v впервые получен. По индукции: все вершины на расстоянии k по числу рёбер обнаруживаются не позднее уровня k. При извлечении из очереди мы обрабатываем вершины в порядке увеличения уровня, поэтому никакая вершина не будет получена с меньшим числом рёбер позже. Следовательно, полученные dist — оптимальны по числу рёбер.
Сложность
OV+EV + EV+E времени и OVVV дополнительной памяти очередь+массивvisited/distочередь + массив visited/distочередь+массивvisited/dist.
3) DFS обходвглубинуобход в глубинуобходвглубину. Применение
Проверка достижимости, компоненты связности внеориентированномв неориентированномвнеориентированном, поиск мостов/точек сочленения, топологическая сортировка черезвременаокончаниячерез времена окончаниячерезвременаокончания.Подходит, когда порядок обхода важен или нужно получать структуру рекурсивных вызовов.
Доказательство корректности длятопологическойсортировкичерезвременаокончаниядля топологической сортировки через времена окончаниядлятопологическойсортировкичерезвременаокончания
Если в DAG есть ребро u → v, то в ходе DFS либо v полностью обойдётся в вызове DFSvvv до того, как закончится DFSuuu (тогда finish(v) < finish(u)), либо DFSuuu не начался до DFSvvv. В любом случае finishuuu > finishvvv. Следовательно, упорядочение по убыванию времени окончания даёт топологический порядок предшественникиидутраньшепотомковпредшественники идут раньше потомковпредшественникиидутраньшепотомков.
Сложность
OV+EV + EV+E времени, OVVV памяти стекрекурсииилиявныйстекстек рекурсии или явный стекстекрекурсииилиявныйстек.
4) Алгоритм Дейкстры. Применение
Взвешенный граф, все веса рёбер ≥ 0, нужен кратчайший путь от одного источника.Практически: карты/роуд-нейтворки — веса дистанции/времядистанции/времядистанции/время неотрицательны → Dijkstra илиA∗еслиестьэвристикаили A* если есть эвристикаилиA∗еслиестьэвристика.
Инвариант: когда вершина u извлекается из приоритетной очереди имеяминимальноетекущееdistимея минимальное текущее distимеяминимальноетекущееdist, её dist окончателен неизменитсяпозднеене изменится позднеенеизменитсяпозднее.Доказательство по противоречию: пусть u извлечена с distuuu = d, но существует путь s → ... → u с суммарным весом d' < d. Рассмотрим первый по пути вершину x ещё не извлечённую т.е.первый«незакреплённый»послеизвлечённыхт.е. первый «незакреплённый» после извлечённыхт.е.первый«незакреплённый»послеизвлечённых; её dist ≤ d' < d, значит очередь должна была извлечь x раньше u. Противоречие. Неотрицательность весов требуется, чтобы при прохождении от извлечённых вершин к не извлечённым расстояния не уменьшались «неожиданно» через уже обработанные вершины.
Сложность
С реализацией через бинарную кучу: O(V+E)logV(V + E) log V(V+E)logV ≈ OElogVE log VElogV для связных графов.С использованием Fibonacci-кучи: OE+VlogVE + V log VE+VlogVредкоиспользуетсявпрактикередко используется в практикередкоиспользуетсявпрактике.С матрицей смежности илибезкучиили без кучиилибезкучи: OV2V^2V2 — удобно для плотных графов.
5) Bellman–Ford. Применение
Наличие отрицательных весов нотребуетсяотсутствиенегативногоцикланадостижимыхвершинах,еслинужноконечноерешениено требуется отсутствие негативного цикла на достижимых вершинах, если нужно конечное решениенотребуетсяотсутствиенегативногоцикланадостижимыхвершинах,еслинужноконечноерешение.Нужна детекция отрицательных циклов, или несколько источников через добавление фиктивного источника.
Доказательство корректности
Любой простой путь содержит ≤ V−1 рёбер. Если после k итераций релаксации всех рёбер все кратчайшие пути, состоящие не более чем из k рёбер, корректно найдены.Индукция: после 0 итераций dist либо 0 источникисточникисточник либо ∞. При очередной полной итерации релаксации всех рёбер корректно обновляются все пути длиной ≤ k+1, так как путь длиной k+1 разбивается на путь длиной k плюс одно ребро; если длина пути минимальна, то длина пути к предпоследней вершине была уже минимальной после k итераций. Следовательно, после V−1 итерации найдены все оптимальные расстояния.Для обнаружения отрицательного цикла достаточно сделать ещё одну итерацию: если какой-то dist уменьшается, значит есть цикл, позволяющий уменьшать суммарный вес бесконечно отрицательныйциклотрицательный циклотрицательныйцикл.
Сложность
OV⋅EV·EV⋅E времени, OVVV памяти. Для больших графов часто дорог.
6) Топологическая сортировка применениеикорректностьприменение и корректностьприменениеикорректность
Применение: упорядочение задач с зависимостями DAGDAGDAG.Методы: Kahn удалениевершинсindegree=0удаление вершин с indegree=0удалениевершинсindegree=0 или DFS обратныйпорядококончанийобратный порядок окончанийобратныйпорядококончаний.Корректность Kahn: в DAG всегда есть вершина с indegree=0 иначециклиначе циклиначецикл. Удаляя такие вершины и их рёбра, получаем корректный порядок; если в процессе нет доступных вершин, значит есть цикл.Оба метода работают за OV+EV + EV+E.
7) Практические рекомендации и дополнительные замечания
Карты/навигация: Dijkstra илиA∗сэвристикойили A* с эвристикойилиA∗сэвристикой — быстрый, веса неотрицательны. Для быстрого многопоиска множествоисточников/целеймножество источников/целеймножествоисточников/целей использовать многопоточность, bidirectional Dijkstra, предварительную маршрутизацию ALT,contractionhierarchiesALT, contraction hierarchiesALT,contractionhierarchies.Сети с отрицательными весами: Bellman–Ford, либо Johnson перевещиваниеперевещиваниеперевещивание: запускаем Bellman–Ford один раз с фиктивным источником, получаем потенциалы hvvv, затем ребра перевешиваем: w'u,vu,vu,v=wu,vu,vu,v+huuu−hvvv ≥ 0, и запускаем Dijkstra из каждой вершины еслинужноall−pairsесли нужно all-pairsеслинужноall−pairs, что даёт общую сложность OVE+V⋅ElogVVE + V·E log VVE+V⋅ElogV ≈ OVE+V⋅ElogVVE + V·E log VVE+V⋅ElogV — выгодно для разреженных графов.Если нужно обнаружить отрицательные циклы — Bellman–Ford прямо даёт инструмент.Для очень больших графов и спецзадач рассмотрите эвристики и индексирование ALT,CHALT, CHALT,CH или приблизительные алгоритмы.
Невзвешенный → BFS.Взвешенный, веса ≥ 0 → Dijkstra heapheapheapеслимногозапросов—рассмотретьпредобработку/индексациюесли много запросов — рассмотреть предобработку/индексациюеслимногозапросов—рассмотретьпредобработку/индексацию.Взвешенный, возможны отрицательные веса → Bellman–Ford дляsingle−source+обнаружениецикловдля single-source + обнаружение цикловдляsingle−source+обнаружениециклов или Johnson дляall−pairsдля all-pairsдляall−pairs.Топологический порядок в DAG → Kahn или DFS.По сложности: BFS/DFS/topo OV+EV+EV+E; Dijkstra OElogVE log VElogVилиO(V2)или O(V^2)илиO(V2); Bellman–Ford OVEVEVE.
Если хотите, могу привести формальные доказательства полныешагииндукцииполные шаги индукцииполныешагииндукции для каждого алгоритма в более развернутом виде, либо схемы реализации и примеры кода для конкретных задач карты,сетисотриц.весами,DAGкарты, сети с отриц. весами, DAGкарты,сетисотриц.весами,DAG.
Кратко — какие критерии выбирать и почему, с доказательствами корректности и оценкой сложности.
1) Критерии выбора обобщённообобщённообобщённо
Если граф не взвешен всерёбраимеют«одинаковый»вес,либоинтересуетминимумчисларёбервсе рёбра имеют «одинаковый» вес, либо интересует минимум числа рёбервсерёбраимеют«одинаковый»вес,либоинтересуетминимумчисларёбер → BFS одинисточникодин источникодинисточник или многопроходный BFS несколькоисточниковнесколько источниковнесколькоисточников.Если взвешен, веса неотрицательные → Dijkstra быстрыйбыстрыйбыстрый.Если возможны отрицательные веса и нужно корректно обработать их и/илиобнаружитьотрицательныециклыи/или обнаружить отрицательные циклыи/илиобнаружитьотрицательныециклы → Bellman–Ford.Если нужно только проверка достижимости, обход всех вершин, компоненты связности, построение порядка при DAG → DFS илиBFSдлянекоторыхзадачили BFS для некоторых задачилиBFSдлянекоторыхзадач.Для топологической сортировки DAG → Kahn BFS−подобныйBFS-подобныйBFS−подобный или DFS поубываниювремениокончанияпо убыванию времени окончанияпоубываниювремениокончания.Если нужны кратчайшие пути между всеми парами вершин: для dense графа — Floyd–Warshall; для sparse с возможными отрицательными весами без негативных циклов — Johnson перевесить+Dijkstraперевесить + Dijkstraперевесить+Dijkstra.Практические соображения: для очень больших разреженных графов использовать Dijkstra с кучей heapheapheap; для плотных графов Dijkstra с матрицей/масивом может быть эффективнее O(V2)O(V^2)O(V2). Bellman–Ford обычно дороже O(VE)O(VE)O(VE), но прост в реализации и даёт обнаружение отрицательных циклов.2) BFS обходвширинуобход в ширинуобходвширину. Применение
Невзвешенные графы: кратчайший путь по числу рёбер.Поиск достижимости, минимальное число шагов, многоточечные волны.Доказательство корректности краткократкократко
BFS строит слои: расстояние distvvv = уровень, на котором v впервые получен. По индукции: все вершины на расстоянии k по числу рёбер обнаруживаются не позднее уровня k. При извлечении из очереди мы обрабатываем вершины в порядке увеличения уровня, поэтому никакая вершина не будет получена с меньшим числом рёбер позже. Следовательно, полученные dist — оптимальны по числу рёбер.Сложность
OV+EV + EV+E времени и OVVV дополнительной памяти очередь+массивvisited/distочередь + массив visited/distочередь+массивvisited/dist.3) DFS обходвглубинуобход в глубинуобходвглубину. Применение
Проверка достижимости, компоненты связности внеориентированномв неориентированномвнеориентированном, поиск мостов/точек сочленения, топологическая сортировка черезвременаокончаниячерез времена окончаниячерезвременаокончания.Подходит, когда порядок обхода важен или нужно получать структуру рекурсивных вызовов.Доказательство корректности длятопологическойсортировкичерезвременаокончаниядля топологической сортировки через времена окончаниядлятопологическойсортировкичерезвременаокончания
Если в DAG есть ребро u → v, то в ходе DFS либо v полностью обойдётся в вызове DFSvvv до того, как закончится DFSuuu (тогда finish(v) < finish(u)), либо DFSuuu не начался до DFSvvv. В любом случае finishuuu > finishvvv. Следовательно, упорядочение по убыванию времени окончания даёт топологический порядок предшественникиидутраньшепотомковпредшественники идут раньше потомковпредшественникиидутраньшепотомков.Сложность
OV+EV + EV+E времени, OVVV памяти стекрекурсииилиявныйстекстек рекурсии или явный стекстекрекурсииилиявныйстек.4) Алгоритм Дейкстры. Применение
Взвешенный граф, все веса рёбер ≥ 0, нужен кратчайший путь от одного источника.Практически: карты/роуд-нейтворки — веса дистанции/времядистанции/времядистанции/время неотрицательны → Dijkstra илиA∗еслиестьэвристикаили A* если есть эвристикаилиA∗еслиестьэвристика.Доказательство корректности классическое«жадное»утверждениеклассическое «жадное» утверждениеклассическое«жадное»утверждение
Инвариант: когда вершина u извлекается из приоритетной очереди имеяминимальноетекущееdistимея минимальное текущее distимеяминимальноетекущееdist, её dist окончателен неизменитсяпозднеене изменится позднеенеизменитсяпозднее.Доказательство по противоречию: пусть u извлечена с distuuu = d, но существует путь s → ... → u с суммарным весом d' < d. Рассмотрим первый по пути вершину x ещё не извлечённую т.е.первый«незакреплённый»послеизвлечённыхт.е. первый «незакреплённый» после извлечённыхт.е.первый«незакреплённый»послеизвлечённых; её dist ≤ d' < d, значит очередь должна была извлечь x раньше u. Противоречие. Неотрицательность весов требуется, чтобы при прохождении от извлечённых вершин к не извлечённым расстояния не уменьшались «неожиданно» через уже обработанные вершины.Сложность
С реализацией через бинарную кучу: O(V+E)logV(V + E) log V(V+E)logV ≈ OElogVE log VElogV для связных графов.С использованием Fibonacci-кучи: OE+VlogVE + V log VE+VlogV редкоиспользуетсявпрактикередко используется в практикередкоиспользуетсявпрактике.С матрицей смежности илибезкучиили без кучиилибезкучи: OV2V^2V2 — удобно для плотных графов.5) Bellman–Ford. Применение
Наличие отрицательных весов нотребуетсяотсутствиенегативногоцикланадостижимыхвершинах,еслинужноконечноерешениено требуется отсутствие негативного цикла на достижимых вершинах, если нужно конечное решениенотребуетсяотсутствиенегативногоцикланадостижимыхвершинах,еслинужноконечноерешение.Нужна детекция отрицательных циклов, или несколько источников через добавление фиктивного источника.Доказательство корректности
Любой простой путь содержит ≤ V−1 рёбер. Если после k итераций релаксации всех рёбер все кратчайшие пути, состоящие не более чем из k рёбер, корректно найдены.Индукция: после 0 итераций dist либо 0 источникисточникисточник либо ∞. При очередной полной итерации релаксации всех рёбер корректно обновляются все пути длиной ≤ k+1, так как путь длиной k+1 разбивается на путь длиной k плюс одно ребро; если длина пути минимальна, то длина пути к предпоследней вершине была уже минимальной после k итераций. Следовательно, после V−1 итерации найдены все оптимальные расстояния.Для обнаружения отрицательного цикла достаточно сделать ещё одну итерацию: если какой-то dist уменьшается, значит есть цикл, позволяющий уменьшать суммарный вес бесконечно отрицательныйциклотрицательный циклотрицательныйцикл.Сложность
OV⋅EV·EV⋅E времени, OVVV памяти. Для больших графов часто дорог.6) Топологическая сортировка применениеикорректностьприменение и корректностьприменениеикорректность
Применение: упорядочение задач с зависимостями DAGDAGDAG.Методы: Kahn удалениевершинсindegree=0удаление вершин с indegree=0удалениевершинсindegree=0 или DFS обратныйпорядококончанийобратный порядок окончанийобратныйпорядококончаний.Корректность Kahn: в DAG всегда есть вершина с indegree=0 иначециклиначе циклиначецикл. Удаляя такие вершины и их рёбра, получаем корректный порядок; если в процессе нет доступных вершин, значит есть цикл.Оба метода работают за OV+EV + EV+E.7) Практические рекомендации и дополнительные замечания
Карты/навигация: Dijkstra илиA∗сэвристикойили A* с эвристикойилиA∗сэвристикой — быстрый, веса неотрицательны. Для быстрого многопоиска множествоисточников/целеймножество источников/целеймножествоисточников/целей использовать многопоточность, bidirectional Dijkstra, предварительную маршрутизацию ALT,contractionhierarchiesALT, contraction hierarchiesALT,contractionhierarchies.Сети с отрицательными весами: Bellman–Ford, либо Johnson перевещиваниеперевещиваниеперевещивание: запускаем Bellman–Ford один раз с фиктивным источником, получаем потенциалы hvvv, затем ребра перевешиваем: w'u,vu,vu,v=wu,vu,vu,v+huuu−hvvv ≥ 0, и запускаем Dijkstra из каждой вершины еслинужноall−pairsесли нужно all-pairsеслинужноall−pairs, что даёт общую сложность OVE+V⋅ElogVVE + V·E log VVE+V⋅ElogV ≈ OVE+V⋅ElogVVE + V·E log VVE+V⋅ElogV — выгодно для разреженных графов.Если нужно обнаружить отрицательные циклы — Bellman–Ford прямо даёт инструмент.Для очень больших графов и спецзадач рассмотрите эвристики и индексирование ALT,CHALT, CHALT,CH или приблизительные алгоритмы.8) Резюме короткиекритериикороткие критериикороткиекритерии
Невзвешенный → BFS.Взвешенный, веса ≥ 0 → Dijkstra heapheapheap еслимногозапросов—рассмотретьпредобработку/индексациюесли много запросов — рассмотреть предобработку/индексациюеслимногозапросов—рассмотретьпредобработку/индексацию.Взвешенный, возможны отрицательные веса → Bellman–Ford дляsingle−source+обнаружениецикловдля single-source + обнаружение цикловдляsingle−source+обнаружениециклов или Johnson дляall−pairsдля all-pairsдляall−pairs.Топологический порядок в DAG → Kahn или DFS.По сложности: BFS/DFS/topo OV+EV+EV+E; Dijkstra OElogVE log VElogV илиO(V2)или O(V^2)илиO(V2); Bellman–Ford OVEVEVE.Если хотите, могу привести формальные доказательства полныешагииндукцииполные шаги индукцииполныешагииндукции для каждого алгоритма в более развернутом виде, либо схемы реализации и примеры кода для конкретных задач карты,сетисотриц.весами,DAGкарты, сети с отриц. весами, DAGкарты,сетисотриц.весами,DAG.