Loading AI tools
алгоритм на графах, изобретённый нидерландским ученым Э. Дейкстрой в 1959 году Из Википедии, свободной энциклопедии
Алгори́тм Де́йкстры (англ. Dijkstra’s algorithm) — алгоритм на графах, изобретённый нидерландским учёным Эдсгером Дейкстрой в 1959 году. Находит кратчайшие пути от одной из вершин графа до всех остальных. Алгоритм работает только для графов без рёбер отрицательного веса. Алгоритм широко применяется в программировании, например, его используют протоколы маршрутизации OSPF и IS-IS.
Вариант 1. Дана сеть автомобильных дорог, соединяющих города Московской области. Некоторые дороги односторонние. Найти кратчайшие пути от города А до каждого города области (если двигаться можно только по дорогам).
Вариант 2. Имеется некоторое количество авиарейсов между городами мира, для каждого известна стоимость. Стоимость перелёта из A в B может быть не равна стоимости перелёта из B в A. Найти маршрут минимальной стоимости (возможно, с пересадками) от Копенгагена до Барнаула.
Дан взвешенный ориентированный[1] граф без дуг отрицательного веса[2]. Найти кратчайшие пути от некоторой вершины графа до всех остальных вершин этого графа.
Каждой вершине из множества вершин V сопоставим метку — минимальное известное расстояние от этой вершины до стартовой вершины a.
Алгоритм работает пошагово — на каждом шаге он «посещает» одну вершину и пытается уменьшать метки.
Работа алгоритма завершается, когда все вершины посещены.
Инициализация.
Метка самой вершины a полагается равной 0, метки остальных вершин — бесконечности.
Это отражает то, что расстояния от a до других вершин пока неизвестны.
Все вершины графа помечаются как непосещённые.
Шаг алгоритма.
Если все вершины посещены, алгоритм завершается.
В противном случае, из ещё не посещённых вершин выбирается вершина u, имеющая минимальную метку.
Мы рассматриваем все возможные маршруты, в которых u является предпоследним пунктом. Вершины, в которые ведут рёбра из u, назовём соседями этой вершины. Для каждого соседа вершины u, кроме отмеченных как посещённые, рассмотрим новую длину пути, равную сумме значений текущей метки u и длины ребра, соединяющего u с этим соседом.
Если полученное значение длины меньше значения метки соседа, заменим значение метки полученным значением длины. Рассмотрев всех соседей, пометим вершину u как посещённую и повторим шаг алгоритма.
Рассмотрим выполнение алгоритма на примере графа, показанного на рисунке.
Пусть требуется найти кратчайшие расстояния от 1-й вершины до всех остальных.
Кружками обозначены вершины, линиями — пути между ними (рёбра графа).
В кружках обозначены номера вершин, над рёбрами обозначен их вес — длина пути.
Рядом с каждой вершиной красным обозначена метка — длина кратчайшего пути в эту вершину из вершины 1.
Первый шаг.
Минимальную метку имеет вершина 1. Её соседями являются вершины 2, 3 и 6.
Первый по очереди сосед вершины 1 — вершина 2, потому что длина пути до неё минимальна.
Длина пути в неё через вершину 1 равна сумме значения метки вершины 1 и длины ребра, идущего из 1-й в 2-ю, то есть 0 + 7 = 7.
Это меньше текущей метки вершины 2, бесконечности, поэтому новая метка 2-й вершины равна 7.
Аналогичную операцию проделываем с двумя другими соседями 1-й вершины — 3-й и 6-й.
Все соседи вершины 1 проверены.
Текущее минимальное расстояние до вершины 1 считается окончательным и пересмотру не подлежит.
Вычеркнем её из графа, чтобы отметить, что эта вершина посещена.
Второй шаг.
Снова находим «ближайшую» из непосещённых вершин. Это вершина 2 с меткой 7.
Снова пытаемся уменьшить метки соседей выбранной вершины, пытаясь пройти в них через 2-ю вершину. Соседями вершины 2 являются вершины 1, 3 и 4.
Первый (по порядку) сосед вершины 2 — вершина 1. Но она уже посещена, поэтому с 1-й вершиной ничего не делаем.
Следующий сосед — вершина 3, так как имеет минимальную метку.
Если идти в неё через 2, то длина такого пути будет равна 17 (7 + 10 = 17). Но текущая метка третьей вершины равна 9, а это меньше 17, поэтому метка не меняется.
Ещё один сосед вершины 2 — вершина 4.
Если идти в неё через 2-ю, то длина такого пути будет равна сумме кратчайшего расстояния до 2-й вершины и расстояния между вершинами 2 и 4, то есть 22 (7 + 15 = 22).
Поскольку 22<, устанавливаем метку вершины 4 равной 22.
Все соседи вершины 2 просмотрены, замораживаем расстояние до неё и помечаем её как посещённую.
Третий шаг.
Повторяем шаг алгоритма, выбрав вершину 3. После её «обработки» получим такие результаты:
Дальнейшие шаги.
Повторяем шаг алгоритма для оставшихся вершин. Это будут вершины 6, 4 и 5, соответственно порядку.
Завершение выполнения алгоритма.
Алгоритм заканчивает работу, когда все вершины посещены.
Результат работы алгоритма виден на последнем рисунке: кратчайший путь от вершины 1 до 2-й составляет 7, до 3-й — 9, до 4-й — 20, до 5-й — 20, до 6-й — 11.
Если в какой-то момент все непосещённые вершины помечены бесконечностью, то это значит, что до этих вершин нельзя добраться (то есть граф несвязный). Тогда алгоритм может быть завершён досрочно.
Ниже приведён код реализации алгоритма на языке программирования Java. Данный вариант реализации не является лучшим, но наглядно показывает возможную реализацию алгоритма:
class Dijkstra {
double[] dist = new double[GV()];
Edge[] pred = new Edge[GV()];
public Dijkstra(WeightedDigraph G, int s) {
boolean[] marked = new boolean[GV()];
for (int v = 0; v <GV(); v++)
dist[v] = Double.POSITIVE_INFINITY;
MinPQplus<Double, Integer> pq;
pq = new MinPQplus<Double, Integer>(); \\Priority Queue
dist[s] = 0.0;
pq.put(dist[s], s);
while (!pq.isEmpty()) {
int v = pq.delMin();
if (marked[v]) continue;
marked(v) = true;
for (Edge e (v)) {
int w = e.to();
if (dist[w]> dist[v] + e.weight()) {
dist[w] = dist[v] + e.weight();
pred[w] = e;
pq.insert(dist[w], w);
}
}
}
}
}
Присвоим
Для всех отличных от присвоим .
Пока . Пусть — вершина с минимальным занесём в
Для всех таких, что
Если то
Изменим
Изменим
В простейшей реализации для хранения чисел d[i] можно использовать массив чисел, а для хранения принадлежности элемента множеству U — массив булевых переменных.
В начале алгоритма расстояние для начальной вершины полагается равным нулю, а все остальные расстояния заполняются большим положительным числом (бо́льшим максимального возможного пути в графе). Массив флагов заполняется нулями. Затем запускается основной цикл.
На каждом шаге цикла мы ищем вершину с минимальным расстоянием и флагом равным нулю. Затем мы устанавливаем в ней флаг в 1 и проверяем все соседние с ней вершины . Если в них (в ) расстояние больше, чем сумма расстояния до текущей вершины и длины ребра, то уменьшаем его. Цикл завершается, когда флаги всех вершин становятся равны 1, либо когда у всех вершин c флагом 0 . Последний случай возможен тогда и только тогда, когда граф G несвязный.
Пусть — длина кратчайшего пути из вершины в вершину . Докажем по индукции, что в момент посещения любой вершины выполняется равенство .
База. Первой посещается вершина . В этот момент .
Шаг. Пусть мы выбрали для посещения вершину . Докажем, что в этот момент . Для начала отметим, что для любой вершины всегда выполняется (алгоритм не может найти путь короче, чем кратчайший из всех существующих). Пусть — кратчайший путь из в . Вершина находится на и не посещена. Поэтому множество непосещённых вершин на непусто. Пусть — первая непосещённая вершина на , — предшествующая ей (следовательно, посещённая). Поскольку путь кратчайший, его часть, ведущая из через в , тоже кратчайшая, следовательно .
По предположению индукции, в момент посещения вершины выполнялось , следовательно, вершина тогда получила метку не больше чем . Следовательно, . Если , то индукционный переход доказан. Иначе, поскольку сейчас выбрана вершина , а не , метка минимальна среди непосещённых, то есть . Комбинируя это с , имеем , что и требовалось доказать.
Поскольку алгоритм заканчивает работу, когда все вершины посещены, в этот момент для всех вершин.
Сложность алгоритма Дейкстры зависит от способа нахождения вершины v, а также способа хранения множества непосещённых вершин и способа обновления меток. Обозначим через n количество вершин, а через m — количество рёбер в графе G.
скрытые константы в асимптотических оценках трудоёмкости велики и использование фибоначчиевых куч редко оказывается целесообразным: обычные двоичные (d-ичные[англ.]) кучи на практике эффективнее.
Альтернативами им служат толстые кучи, тонкие кучи и кучи Бродала[англ.], обладающие теми же асимптотическими оценками, но меньшими константами[4].
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.