Скачать презентацию Алгоритмы на графах План лекции n n n Скачать презентацию Алгоритмы на графах План лекции n n n

Графы-2.ppt

  • Количество слайдов: 22

Алгоритмы на графах План лекции: n n n Основные определения. Формы представления графов. Поиск Алгоритмы на графах План лекции: n n n Основные определения. Формы представления графов. Поиск по графу в глубину, его применения. Поиск по графу в ширину. Кратчайшие пути в графе. Минимальные остовные деревья. автор: С. Н. Дроздов

Основные определения n n n Число вершин N = 5. n Число ребер M Основные определения n n n Число вершин N = 5. n Число ребер M = 9. n 2 G = (V, E); V – вершины, E – ребра (дуги). Ориентированные (орграфы) / неориентированные. Связные графы (есть путь из любой вершины в любую); сильно связные орграфы (есть ориентированный путь из любой в любую). Связные компоненты графа, сильно связные компоненты орграфа. Полный граф (есть ребра между всеми вершинами). Цикл (замкнутый путь); ориентированный цикл. Дерево (связный граф без циклов). Подграф (подмножество вершин и все ребра между ними).

Оценка количества ребер n Для полного графа (без петель): q q n Для произвольного Оценка количества ребер n Для полного графа (без петель): q q n Для произвольного графа: q q n ориентированного: M = N * (N – 1); неориентированного: M = N * (N – 1) / 2; ориентированного: 0 <= M <= N * (N – 1); неориентированного: 0 <= M <= N * (N – 1) / 2; Для дерева: q M = N – 1. 3

4 Формы представления графов Списки смежности Список ребер Матрица смежности 1 2 3 4 4 Формы представления графов Списки смежности Список ребер Матрица смежности 1 2 3 4 5 1 0 0 0 1 1 2 1 0 0 1 0 3 1 1 0 0 0 4 0 0 1 1 0 5 1 0 0 1 5 1 2 1 3 4 4 4 5 1 2 3 3 4 2 4 1 1 2 3 4 5 • • • 2 3 3 5 4 4 1 2 1 • x x • x

Помеченные графы n n n Пометки – числа или другие величины (например, цвета), поставленные Помеченные графы n n n Пометки – числа или другие величины (например, цвета), поставленные в соответствие вершинам и/или ребрам графа. В зависимости от задачи, пометки могут иметь смысл длины, стоимости, веса, сопротивления, трудоемкости и т. п. Формы представления – в основном те же, с необходимыми модификациями. Например, в матрице смежности можно хранить не 0/1, а длину ребра (в случае отсутствия ребра - ). 5

Поиск по графу в глубину type Vertex =. . . {Тип данных для вершины; Поиск по графу в глубину type Vertex =. . . {Тип данных для вершины; возможно, просто Integer} var visited: Array[1. . N] of Boolean; {Уже были здесь? } {Инициализируется False} procedure DFS(v: Vertex); {Deep-First Search} var w: Vertex; begin visited[v] : = True; {Здесь возможна обработка вершины v} for (каждая вершина w, смежная с v) do if not visited[w] then DFS(w); {И здесь возможна обработка вершины v} end; Если граф не связен, или в орграфе не все вершины достижимы из начальной, то в visited останутся элементы False. Можно повторять поиск: for v : = 1 to N do if not visited[v] then DFS(v); Трудоемкость: T(N, M) = O(N + M) 6

Применения поиска в глубину (1): n n Проверка связности, выделение связных компонент. Поиск пути Применения поиска в глубину (1): n n Проверка связности, выделение связных компонент. Поиск пути (какого-нибудь) между заданными вершинами. Проверка наличия циклов и ориентированных циклов: q q при рекурсивном входе в вершину помечать ее как «просматриваемую» , а перед выходом снимать эту пометку; если из текущей вершины есть ребро в другую «просматриваемую» вершину, то это цикл. 7

Применения поиска в глубину (2): n Топологическая сортировка. Ациклический орграф является топологически отсортированным, если Применения поиска в глубину (2): n Топологическая сортировка. Ациклический орграф является топологически отсортированным, если его вершины пронумерованы так, что дуги ведут только из вершины с меньшим номеров в вершину с большим. (Или, более наглядно: все вершины выстроены в линию так, что все дуги идут слева направо. ) Для топологически отсортированного графа можно за один проход слева направо подсчитать много полезного: максимальную / минимальную длину пути между двумя вершинами, количество разных путей и т. п. 8

Алгоритм топологической сортировки Выполняется DFS, причем вершины нумеруются в порядке выхода из рекурсивной процедуры. Алгоритм топологической сортировки Выполняется DFS, причем вершины нумеруются в порядке выхода из рекурсивной процедуры. n Повторять, пока остались непройденные вершины. n В результате имеем топологическую сортировку в порядке уменьшения полученных номеров. var visited: array[1. . N] of Boolean; exit. Numb: array [1. . N] of Integer; const count: Integer = N; procedure DFS_TS(v: Vertex); var w: Vertex; begin visited[v] : = True; for (каждая вершина w, смежная с v) do if not visited[w] then DFS(w); exit. Numb[v] : = count; count : = count – 1; end; . . . for v : = 1 to N do begin if not visited[v] then DFS(w); TSOrder[exit. Numb[v]] : = v; end; n 9

Поиск по графу в ширину Основная идея: все нерассмотренные вершины, смежные с текущей, заносятся Поиск по графу в ширину Основная идея: все нерассмотренные вершины, смежные с текущей, заносятся в очередь, и затем очередная вершина выбирается из очередь. Другое название – «волновой алгоритм» . type Queue =. . . {Тип очереди с операциями Put (поставить в очередь), Get (взять из очереди), Empty (проверка пустоты)} var visited: Array[1. . N] of Boolean; procedure BFS(v: Vertex); {Breadth-First Search} var Q: Queue; u, w: Vertex; begin visited[v] : = True; Put(Q, v); while not Empty(Q) do begin Get(Q, u); for (каждая вершина w, смежная с u) do if not visited[w] then begin visited[w] : = True; Put(Q, w); end; Трудоемкость: T(N, M) = O(N + M). Пример применения: поиск кратчайшего пути из лабиринта. 10

Реализация очереди для поиска в ширину n n n Поскольку каждая вершина может побывать Реализация очереди для поиска в ширину n n n Поскольку каждая вершина может побывать в очереди только один раз, для представления очереди достаточно использовать массив из N элементов и указатели на голову и на хвост. Инициализация: Head : = 1; Tail : = 1; Put(Q, x): Q[Tail] : = x; Tail : = Tail + 1; Get(Q, x): x : = Q[Head]; Head : = Head + 1; Empty(Q): Empty : = (Head = Tail); 11

Кратчайшие пути в графе: алгоритм Флойда n n n Дан орграф G = (V, Кратчайшие пути в графе: алгоритм Флойда n n n Дан орграф G = (V, E), матрица длин ребер {bij} (если ребра нет, bij = ). Ограничение: нет циклов отрицательной длины. Построить матрицу длин кратчайших путей для всех пар ребер {lij}. Основная идея: динамическое программирование. q На шаге 0: положить {lij} : = {bij} (только пути по прямому ребру из i в j). q На шаге k: пересчитать все от i до j расстояния с учетом возможности использовать вершину k как промежуточную: lij : = min (lij, lik + lkj); q n n После шага N имеем матрицу минимальных длин путей. Чтобы найти сам кратчайший путь, можно параллельно с {lij} строить матрицу {tij} , где tij – номер предпоследней вершины на кратчайшем пути от i к j. Сначала все tij : = i, а на шаге k, если меняется lij: = lik + lkj, то tij : = tkj. Трудоемкость: T(N, M) = O(N 3). 12

Пример на алгоритм Флойда Найдем кратчайший путь из 1 в 3, пользуясь матрицами L Пример на алгоритм Флойда Найдем кратчайший путь из 1 в 3, пользуясь матрицами L 3 и T 3. Длина пути равна l 13 = 15. Элемент t 13 = 2, т. е. предпоследней вершиной пути будет 2. Элемент t 12 = 2, т. е. перед вершиной 2 идет 1. Имеем путь 1 2 3. 13

Кратчайшие пути в графе: алгоритм Дейкстры n n n Дан орграф G = (V, Кратчайшие пути в графе: алгоритм Дейкстры n n n Дан орграф G = (V, E), матрица длин ребер {bij} (если ребра нет, bij = ). Ограничение: длина всех ребер неотрицательная. Даны две вершины X и Y. Построить кратчайший путь из X в Y. Основная идея: использовать ту же формулу пересчета, что в алгоритме Флойда, но рассматривать только те вершины, которые лежат на путях, выходящих из X. Трудоемкость: T(N, M) = O(N 2). 14

Описание алгоритма Дейкстры var B: array[1. . N, 1. . N] of TLength; U: Описание алгоритма Дейкстры var B: array[1. . N, 1. . N] of TLength; U: set of 1. . N; L: array [1. . N] of Integer; X, Y: Vertex; . . . for i: = 1 to N do L[i]: = ; L[X] : = 0; t : = X; U : = [1. . N]; repeat U : = U – [t]; for w: (есть дуга t->w) & (w in U) do L[w] : = min(L[w], L[t] + B[p, w]); k : = номер вершины из U с минимальным значением l[k]; t : = k; until t = Y; 15 U – множество вершин, для которых пока неизвестно расстояние от X. L – массив оценок расстояний вершин от X. t – та из вершин V, для которой оценка расстояния минимальна. Можно доказать, что эта оценка и есть мин. расстояние t от X. Исключаем t из множества V. Выбрав очередную вершину t, уточняем оценки расстояния для тех оставшихся вершин V, в которые ведет дуга из t. И так далее, пока в качестве t не будет выбрана вершина Y. Можно также продолжить работу и найти расстояния от A до всех достижимых вершин.

16 Пример на алгоритм Дейкстры Ш а г 1 2 3 4 5 1 16 Пример на алгоритм Дейкстры Ш а г 1 2 3 4 5 1 – 0 2 – 30 – 12 + 3 – – 25 – 22 + 4 Ищем кратчайшие пути из 4 во все вершины. 0 + 0 0 5 – – 20 – t 4 + 1 0 + + 2 0 + + + 0 + 20 + 5 Последний столбец содержит длины кратчайших путей. Сами пути можно определить обратным ходом по таблице, по тем значениям t, при которых менялась длина пути, например: 3 2 1 4 0 3

Задача о минимальном остовном дереве n n n Остовное дерево (каркас) связного неориентированного графа Задача о минимальном остовном дереве n n n Остовное дерево (каркас) связного неориентированного графа – любое дерево, содержащее все вершины графа и часть его ребер. Если задана длина ребер графа, то минимальное остовное дерево – то, у которого наименьшая сумма длин ребер. Основная идея алгоритмов поиска мин. остовного дерева: следует выбирать кратчайшие ребра, но при этом избегать появления циклов. 17

Алгоритм Прима 18 Основная идея: начав с произвольной вершины, на каждом шаге добавлять в Алгоритм Прима 18 Основная идея: начав с произвольной вершины, на каждом шаге добавлять в дерево ту вершину, которая смежна с любой из вершин, ранее включенных в дерево, по самому короткому ребру. var B: array[1. . N, 1. . N} of Integer; {Длины ребер} Near: array[1. . N] of Vertex; {Ближайшая вершина дерева} Min. Len: array[1. . N] of Integer; {Расстояние до нее} begin for i : = 2 to N do begin {Сначала в дереве только вершина 1} Near[i] : = 1; Min. Len[i] : = B[i, 1]; end; for i : = 1 to N-1 do begin {Добавить ребро N-1 раз} Найти вершину k с минимальным значением Min. Len[k]; Включить ребро (k, Near[k]) в дерево; Min. Len[k] : = ; {Чтобы второй раз не выбрать эту вершину} for j : = 2 to N do {Корректируем расстояния до дерева} if (Min. Len[j] < ) and (B[k, j] < Min. Len[j]) then begin Min. Len[j] : = B[k, j]; Near[j] : = k; end; Трудоемкость: T(N, M) = O(N 2)

19 Пример на алгоритм Прима Ш а г 2 3 4 2 1/12 – 19 Пример на алгоритм Прима Ш а г 2 3 4 2 1/12 – – 3 1/25 4/18 2/10 – 4 1/0 – – – 5 1/12 (1 -4) Вершина 1 (1 -2) (2 -3) (1 -5) Общая длина ребер остовного дерева L = 0 + 12 = 34

Алгоритм Крускала (Краскала? ) n n Основная идея: заранее отсортировав ребра по длине, выбирать Алгоритм Крускала (Краскала? ) n n Основная идея: заранее отсортировав ребра по длине, выбирать самые короткие их них, следя только, чтобы не построить цикл. Когда число ребер будет N-1, они волейневолей образуют остовное дерево. Чтобы избежать циклов, для каждой вершины будем хранить номер ее компоненты связности (изначально каждая вершина образует отдельную компоненту). При добавлении ребра их компоненты объединяются. Нельзя добавлять ребра, соединяющие две вершины из одной компоненты (это даст цикл). Наиболее удобная форма представления графа – список ребер. Трудоемкость: T(N, M) = O(M*log(M)). Эта оценка может быть лучше, чем для алгоритма Прима, если в графе мало ребер (т. е. M << N 2). 20

Программа алгоритма Крускала 21 var Edges: array[1. . M] of record {Массив ребер} x, Программа алгоритма Крускала 21 var Edges: array[1. . M] of record {Массив ребер} x, y: Vertex; {между какими вершинами} len: Integer; {длина ребра} end; Mark: array[1. . N] of Integer; {Компоненты связности для вершин} procedure Add. Edge(var k: Integer); {Добавление ребра в дерево} begin repeat {Нельзя соединять вершины из} k : = k + 1; {одной компоненты, это будет цикл} xk : = Edges[k]. x; yk : = Edges[k]. y; until Mark[xk] <> Mark[yk]; Включить ребро (xk, yk) в дерево; mark_yk : = Mark[yk]; for i : = 1 to N do {Все вершины из той компоненты, } if Mark[i] = mark_yk then {где была вершина yk, перенести} Mark[i] : = Mark[xk]; {в компоненту xk} end; begin Отсортировать массив Edges по возрастанию длины; for i : = 1 to N do Mark[i] : = i; {Каждая вершина – отдельная компонента} k : = 0; {Начинаем с кратчайшего ребра} while k < N – 1 do {Добавляем до N-1 ребер} Add. Edge(k); end;

22 Пример на алгоритм. РКрускала е б р а 0 10 12 12 18 22 Пример на алгоритм. РКрускала е б р а 0 10 12 12 18 25 30 1 -4 2 -3 1 -2 1 -5 3 -4 1 -3 2 -4 Ш а г Компоненты 0 1 2 3 4 1 1 1 2 2 1 1 3 3 3 2 1 1 4 4 1 1 5 5 5 1 (1 -4) (2 -3) (1 -2) (1 -5) Общая длина ребер остовного дерева L = 0 + 12 = 34