Лекция 9,8. Графы, алгоритм Дейкстры

TODO: теория по графам

Представление графов в памяти компьютера

В множестве вершин V, состоящем из N вершин обычно каждую вершину представляют как целое число от 0 до N - 1 включительно. То есть, просто нумеруют вершины от 0.

С представлением рёбер E возможно большее разнообразие и существует три вида представлений:

  1. Представление в виде списка всех рёбер. Ребро – это тройка (i, j, w), где i и j – вершины из диапазона от 0 до N - 1 включительно. w – вес ребра (i, j)
  2. Представление в виде матрицы смежности. Представлена в памяти в виде двумерного массива arr2d размером N на N. Элемент arr2d[i][j] хранит значение 1, если ребро (i, j) есть и 0, если такого ребра нет. Веса можно хранить отдельно в ещё одном двумерном массиве такого же размера, либо в этом же массиве arr2d вместо единиц, если в графе гарантированно не будет рёбер с весом 0.
  3. Представление в виде списков смежности. Список neighbours[i] содержит пары (j, w), где j – смежная с i вершина, а w – вес вершины (i, j).

Для разреженных графов, где число рёбер много меньше квадрата числа вершин, лучше всего использовать третье представление. Оно даёт экономию памяти и возможность быстрого перебора соседних с данной вершин.

Так же во всех представлениях не нужно забывать, что при вводе неориентированного графа нужно добавлять как прямое ребро (i, j, w), так и обратное (j, i, w). Тогда алгоритмы, рассчитанные на ориентированные графы будут корректно работать и с неориентированными.

Алгоритм Дейкстры

На входе:

V
Множество вершин
E
множество рёбер с их весами
a
начальная вершина

На выходе:

dist
массив, в котором dist[i] – длина кратчайшего пути из вершины a в вершину i

Медленный вариант алгоритма за \(O(N^{2})\) (линейный поиск в массивах dist и visited):

dist = массив из N элементов
заполнить все элементы dist значением "бесконечность"
dist[a] = 0
visited = массив из N элементов
заполнить все элементы значением "ложь"
цикл N раз {
    u = вершина с минимальным dist[i] и ложным visited[i]
    цикл по всем вершинам v, смежным с вершиной u {
        если dist[v] > dist[u] + вес(u, v) {
            dist[v] = dist[u] + вес(u, v)
        }
    }
    visited[u] = истина
}

Более быстрый вариант предполагает использование очереди с приоритетами на основе кучи и имеет время работы O(N * log(N)).