16
Теория графов Родоначальником теории графов принято считать математика Леонарда Эйлера (1707-1783). Однако теория графов многократно переоткрывалась разными авторами при решении различных прикладных задач. Задача о Кенигсбергских мостах. На рис. 1 представлен схематический план центральной части города Кенигсберг (ныне Калининград), включающий два берега реки Перголя, два острова в ней и семь соединяющих мостов. Задача состоит в том, чтобы обойти все четыре части суши, пройдя по каждому мосту один раз, и вернуться в исходную точку. Эта задача была решена (показано, что решение не существует) Эйлером в 1736 году. рис. 1 Задача о трех домах и трех колодцах. Имеется три дома и три колодца, каким-то образом расположенные на плоскости. Провести от каждого дома к каждому колодцу тропинку так, чтобы тропинки не пересекались (рис. 2). Эта задача была решена (показано, что решение не существует) Куратовским в 1930 году. рис. 2 Неформально, граф можно определить как набор вершин (города, перекрестки, компьютеры, буквы, цифры кости домино, микросхемы, люди) и связей между ними: дороги между городами; улицы между перекрестками; проводные линии связи между компьютерами; слова, начинающиеся на одну букву и закачивающиеся на другую или эту же букву; проводники, соединяющие микросхемы; родственные отношения, например, Алексей - сын Петра. 1

теория графов

  • Upload
    di2008

  • View
    207

  • Download
    6

Embed Size (px)

Citation preview

Page 1: теория графов

Теория графов

Родоначальником теории графов принято считать математика Леонарда Эйлера (1707-

1783). Однако теория графов многократно переоткрывалась разными авторами при решении

различных прикладных задач.

Задача о Кенигсбергских мостах. На рис. 1 представлен схематический план

центральной части города Кенигсберг (ныне Калининград), включающий два берега реки

Перголя, два острова в ней и семь соединяющих мостов. Задача состоит в том, чтобы обойти

все четыре части суши, пройдя по каждому мосту один раз, и вернуться в исходную точку. Эта

задача была решена (показано, что решение не существует) Эйлером в 1736 году.

рис. 1

Задача о трех домах и трех колодцах. Имеется три дома и три колодца, каким-то

образом расположенные на плоскости. Провести от каждого дома к каждому колодцу

тропинку так, чтобы тропинки не пересекались (рис. 2). Эта задача была решена (показано,

что решение не существует) Куратовским в 1930 году.

рис. 2

Неформально, граф можно определить как набор вершин (города, перекрестки,

компьютеры, буквы, цифры кости домино, микросхемы, люди) и связей между ними: дороги

между городами; улицы между перекрестками; проводные линии связи между компьютерами;

слова, начинающиеся на одну букву и закачивающиеся на другую или эту же букву;

проводники, соединяющие микросхемы; родственные отношения, например, Алексей - сын

Петра.

1

Page 2: теория графов

ОСНОВНЫЕ СВОЙСТВА ГРАФОВ

Определение: Графом G(V,E) называется совокупность двух множеств – непустого

множества V (множества вершин) и множества E двухэлементных подмножеств множества V

(E – множество ребер).Говорят, что ребро (a, b) соединяет вершины a и b. Если ребро e соединяет вершину a с

вершиной b и пара (a,b) считается упорядоченной, то это ребро называется ориентированным,

вершина a – его началом, вершина b – концом. Если же эта пара считается неупорядоченной,

то ребро называется неориентированным, а обе вершины – его концами.

Ориентированным называется граф, в котором – множество упорядоченных

пар вершин вида (x,y), где x называется началом, а y – концом дуги. Дугу (x, y) записывают как

.

Если элементом множества E может быть пара одинаковых (не различных) элементов V,

то такой элемент множества E называется петлей, а граф называется графом с петлями (или

псевдографом).

Вершины, соединенные ребром, называются смежными. Ребра, имеющие общую

вершину, также называются смежными.

Ребро и любая из его двух вершин называются инцидентными.

Степенью вершины в неорентированном графе называется количество ребер,

соединяющих ее с другими вершинами. Вершина, степень которой равна 0, называется

изолированной. В ориентированном графе степень вершины равна сумме ее входящей и

исходящей степеней.

Маршрут в графе – это последовательность вершин x1, x2, …, xn, такая, что для каждого

i = 1, 2, …, n-1 вершины xi и xi+1 соединены ребром. Эти n-1 ребер называются ребрами

маршрута. Говорят, что маршрут проходит через них, а число n-1 называют длиной

маршрута. Говорят, что маршрут соединяет вершины x1 и xn, они называются соответственно

началом и концом маршрута, вершины x2, …, xn-1 называются промежуточными. Маршрут

называется замкнутым, если x1 = xn.

Путь – это маршрут, в котором все ребра различны. Путь называется простым, если и

все вершины в нем различны.

Цикл – это замкнутый путь. Цикл x1, x2, …, xn-1, x1 называется простым, если все

вершины x1, x2, …, xn-1 попарно различны. Граф без циклов называется ациклическим.

В графе на рис.3 последовательность вершин

2

Page 3: теория графов

2, 3, 5, 4 – не маршрут;

2, 3, 4, 5, 1, 4, 3 – маршрут, но не путь;

3, 1, 4, 5, 1, 2 – путь, но не простой;

2, 3, 1, 4, 5, 1, 2 – цикл, но не простой;

2, 3, 4, 5, 1, 2 – простой цикл.

Рис. 3. Обыкновенный граф.

Неориентированный граф называется связным, если в нем для любых двух вершин

имеется маршрут, соединяющий эти вершины. Ориентированный граф называется связанным,

если для любых двух вершин a и b имеется маршрут от a до b и маршрут от b до a.

Множество всех достижимых вершин называются связными компонентами графа.

Некоторые виды графов имеют специальные названия.

Полным называется неориентированный граф, в котором каждая пара вершин являются

смежными.

Ациклический неориентированный граф называется лесом, а связанный ациклический

неориентированный граф – деревом.

ПРЕДСТАВЛЕНИЕ ГРАФА

Для представления графа в памяти компьютера используются следующие способы:

1) в виде множества списков смежных вершин;

2) в виде матрицы смежности.

Списки смежности.

Представление графа в виде списков смежности использует массив из |V| списков, по

одному для каждой вершины из V. Для каждой вершины a перечисляются все смежные с ней

вершины, т.е. элементы множества V(a). Такой способ задания дает возможность быстрого

просмотра окрестности вершины. Например, на рис.4 представлен граф списками смежности,

в котором содержатся пары связанных между собой элементов (вершин): (1,2), (1,4), (2,3),

(2,5), (2,6), (3,6), (4,5)

3

1

2 4 53

212122

436543

123456

1 2

4 5

3

6

/

////

5 6 /

Page 4: теория графов

Рис. 4. Список смежности для неориентированного графа.

Матрица смежности.

Представление графа с помощью матрицы смежности предполагает, что вершины

пронумерованы в некотором порядке числами 1, 2, …, |V|. В этом случае представление графа

G с помощью матрицы смежности представляет собой матрицу A=(aij) размером |V|x|V| такую,

что

На рис.5 показан граф с занумерованными вершинами и его матрицы смежности.

Рис.5. Пример неориентированного графа.

Матрица смежности:

ОБХОД ГРАФОВ

Поиск в графе – это алгоритмический метод обхода графа, в основе которого лежит

систематический перебор вершин графа, такой что каждая вершина просматривается только

один раз.

1) Поиск в глубину (Depth First Search).

Введем следующие понятия:

Вершину, которая еще не посещена, будем называть новой. В результате посещения

вершина становится открытой и остается такой, пока не будут исследованы все инцидентные

ей ребра. После этого она превращается в закрытую.

Стратегия поиска в глубину состоит в том, чтобы идти вглубь графа, пока это

возможно. При выполнении поиска в глубину исследуются все ребра, выходящие из

последней открытой вершины, и мы покидаем вершину только тогда, когда не остается

неисследованных выходящих из нее ребер. При этом происходит возврат в вершину, из

которой была открыта текущая вершина. Этот процесс продолжается до тех пор, пока не

4

1

2 3

4 65

Page 5: теория графов

будут открыты все вершины, достижимые из исходной. Если при этом остаются неоткрытые

вершины, то одна из них выбирается в качестве новой исходной вершины, и поиск

возобновляется из нее. Процесс повторяется до тех пор, пока не будут открыты все вершины

графа.

При поиске в глубину в качестве активной выбирается та из открытых вершин, которая

была посещена последней. Для реализации такого правила выбора наиболее удобной

структурой хранения множества открытых вершин является стек: открываемые вершины

складываются в стек в том порядке, в каком они открываются, а в качестве активной

выбирается последняя вершина.

На рис.6 у вершин в скобках указана та очередность, в которой вершины графа

просматривались в процессе поиска в глубину.

Рис. 6. Пример обхода графа (поиск в глубину).

Рассмотрим процедуру реализующая обход графа в глубину:

Пусть элементы вектора Visited[1..n] определяет состояние вершины, т.е.

Visited[i]=true, если вершина просмотрена, false иначе.

Матрица A[n,n] определяет матрицу смежности заданного графа.

Program Depth_First;

var

  A: array [1..20, 1..20] of 0..1;

  visited: array [1..20] of boolean;

I,j,n:integer;

procedure dfs(v: integer); {v текущая вершина}

var    i: integer;

begin

   writeln(v); {вершина v не посещалась}

   visited[v]:= true;

   for i:= 1 to n do

      if (a[v,i]=1) and (not visited[i]) then

5

Page 6: теория графов

dfs(i);

end;

 procedure graph_dfs;

var   i: integer;

begin

  for i:= 1 to n do

visited[i]:=false;

  for i:= 1 to n do

      if not visited[i] then

        dfs(i);

 end;

begin

write('n= '); readln(n);

for i:=1 to n do

for j:=i+1 to n do

begin

write('Versina ',i,',',j,'= ');

readln(A[i,j]);

A[j,i]:=A[i,j]

end;

graph_dfs;

end.

Процедура помечает вершину V, затем проходит по всем вершинам и проверяет

каждую вершину, если она не помечена и смежная с данной вершиной V, то запускается от

нее.

2) Поиск в ширину (Breadth First Search)

Суть заключается в том, чтобы рассмотреть все вершины, связанные с текущей.

Принцип выбора следующей вершины для вершины a – выбирается та, которая была раньше

рассмотрена, т.е. находящиеся от нее на расстоянии 1, затем вершины, находящиеся от a на

расстоянии 2, и т.д.

Для реализации данного принципа необходима структура данных очередь, когда новая

вершина становится открытой, она добавляется в конец очереди, а активная выбирается в ее

начале.

Основная особенность поиска в ширину, отличающая его от других способов обхода

графов, состоит в том, что в качестве активной вершины выбирается та из открытых, которая

6

Page 7: теория графов

была посещена раньше других. Именно этим обеспечивается главное свойство поиска в

ширину: чем ближе вершина к старту, тем раньше она будет посещена.

На рис.7 рядом с вершинами в скобках указана очередность просмотра вершин графа.

Рис.7. Пример обхода графа (поиск в ширину).

Procedure DFS (m:Integer);

Var

Q:Array [1..20] Of integer; {Очередь}

head,tail:Integer;{Указатели очереди, head – номер текущей

вершины; tail – новые вершины, помещаемые в «хвост» очереди q}

visited: Array [1..20] Of Boolean; {отмечает уже пройденные

вершины}

i,v,k:Integer;

Begin

head:=1; tail:=1; {Начальная инициализация}

For i:=1 to n do

Visited[i]:=False;

q[tail]:=m;

visited[m]:=true; {B очередь помещаем вершину m}

while head<=tail do {Пока очередь не пуста} begin

v:=q[head];

head:=head+1;

write(v); {Берем элемент из очереди}

For k:=1 to n do {Просмотр всех вершин, связанных с

вершиной v}

if (A[v,k]<>0) and (not Visited[k]) then

{Если вершина ранее не просмотрена, то заносим её номер в

очередь}

begin

7

Page 8: теория графов

tail:=tail+1;

q[tail]:=k;

Visited[k]:=True;

end;

end;

End;

КРАТЧАЙШИЕ ПУТИ

Дан ориентированный граф G = <V,E>, веса дуг – A[i,j] (i,j=l..N, где N – количество

вершин графа), начальная и конечная вершины – s, t V. Веса дуг записаны в матрице

смежности А, если вершины i и j не связаны дугой, то A[i,j] = 0. Путь между s и t оценивается

суммой . Необходимо найти путь с минимальной оценкой. Оценку пути назовем

его весом или длиной.

Пример. Кратчайший путь в графе на рис.8. из вершины 1 в вершину 4 проходит через

3-ю и 2-ю вершины и имеет оценку 6.

Рис. 8. Ориентированный взвешенный граф.

Нам необходимо найти кратчайший путь, т. е. путь с минимальным весом, между

двумя вершинами графа. Эта задача разбивается на две подзадачи: сам путь и значение

минимального веса. Обозначим ее через D[s] как Array[1..N] Of Integer и на каждом шаге

определяем оценки от вершины s до всех остальных вершин графа.

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

Дан ориентированный или неориентированный взвешенный граф с n вершинами и m

рёбрами. Веса всех рёбер неотрицательны. Указана некоторая стартовая вершина s. Требуется

найти длины кратчайших путей из вершины s во все остальные вершины и вывести сам

кратчайший путь.

Эта задача называется "задачей о кратчайших путях с единственным источником"

(single-source shortest paths problem).

Алгоритм

8

3

1

6

252

1 4

3

Page 9: теория графов

Опишем алгоритм, который предложил датский исследователь Дейкстра (Dijkstra) в

1959 г.

Определим массив d[], в котором для каждой вершины v будем хранить текущую длину

d[v] кратчайшего пути из s в v. Изначально записываем в d[s]=0 и в d[v] значения A[s,v], если

они достижимы из вершины s, а для всех остальных вершин эта длина равна бесконечности

(достаточно большое число, заведомо большее возможной длины пути): d[v] = ∞

Кроме того, для каждой вершины v будем хранить, помечена она ещё или нет, т.е.

определим массив visited[]. Изначально все вершины не помечены, т.е. visited [v]=true, если

вершина уже рассмотрена, и visited[v]=false, если нет. Изначально заполняем массив u

значениями false (вершины не обработаны) и visited [s]=true.

Определим массив p[], такой что p[v] – номер вершины, из которой нужно идти в

вершину v в текущем кратчайшем пути, т.е. предпоследняя вершина пути.

Изначально заполнить массив p значением s. Кратчайший путь можно будет

восстановить по нему, каждый раз беря предка от текущей вершины, пока мы не придём в

стартовую вершину s – так мы получим искомый кратчайший путь, но записанный в обратном

порядке.

P = (s, …, p[p[p[v]]], p[p[v]], p[v], v)

Алгоритм Дейкстры состоит из n итераций. На очередной итерации выбирается

вершина i с наименьшей величиной d[v] среди ещё не помеченных, т.е.:

На первой итерации выбрана будет стартовая вершина s.

Выбранная таким образом вершина v отмечается помеченной. Далее, на текущей

итерации, из вершины v производятся улучшения (релаксации): просматриваются все рёбра

(v,x), исходящие из вершины v, и для каждой такой вершины x алгоритм пытается улучшить

значение d[x], тогда:

d[x] = min (d[x], d[v] + A[v,x])

При каждой успешной релаксации, т.е. когда из выбранной вершины v происходит

улучшение расстояния до некоторой вершины x, мы записываем, что предком вершины x

является вершина v: p[x] = v

На этом текущая итерация заканчивается, алгоритм переходит к следующей итерации

(снова выбирается вершина с наименьшей величиной d, из неё производятся релаксации, и

т.д.). После n итераций, все вершины графа станут помеченными, и алгоритм свою работу

завершает. Утверждается, что найденные значения d[v] и есть искомые длины кратчайших

путей из s в v.

9

Page 10: теория графов

Инициализация:

1 2 3 4 5 6

Visited 1 0 0 0 0 0

D 0 7 9 ∞ ∞ 14

P 1 1 1 1 1 1

Шаг 1:

Р

Шаг 2:

10

1 2 3 4 5 6

Visited 1 1 0 0 0 0

D 0 7 9 22 ∞ 14

P 1 1 1 2 1 1

1 2 3 4 5 6

Visited 1 1 1 0 0 0

D 0 7 9 20 ∞ 11

P 1 1 1 3 1 3

Page 11: теория графов

Шаг 3:

Шаг 4 и Шаг 5 массивы не изменяются. В результате получим:

Маршрут из вершины 1 в вершину 5 будет:

Const

inf=65535;

type

matrix=array[1..50,1..50] of word;

var

D:array[1..100] of word; //массив кратчайших расстояний

P:array[1..100] of word; //массив вершин предков в кратчайшем

пути

visited:array[1..100] of boolean; //отмечаем, если посетили

A:Matrix;

s,i,j,n:integer;

procedure Deisktr (A : Matrix; N, s : integer);

var i, j, v, min, x, t, u: longint;

begin

for i:=1 to N do

begin

If A[s,i]<>0 then D[i]:=A[s,i] //изначальный массив расстояний

Else D[i]:=inf;

P[i]:=s;

11

1 2 3 4 5 6

Visited 1 1 1 0 0 1

D 0 7 9 20 20 11

P 1 1 1 3 6 3

1 2 3 4 5 6Visited 1 1 1 1 1 1

D 0 7 9 20 20 11P 1 1 1 3 6 3

Page 12: теория графов

visited[i]:=false;

end;

visited[s]:=TRUE; //вершина S посещена d[s]:=0;

for i:=1 to n-1 do // на каждом шаге находим минимальное решение и пытаемся его улучшить

begin

min:=inf;

for j:=1 to N do

if (not visited[j]) and (D[j] < min) then

begin

min:=D[j]; //минимальное расстояние

v:=j; //найденная вершина

end;

visited[v]:=TRUE; //и она отмечается посещенной

for x:= 1 to N do

if (D[x]>D[v]+A[v,x]) and (not visited[x]) and (A[v,x]<>0) then //пытаемся улучшить решение. Если в ней расстояние больше, чем сумма расстояния до текущей вершины и длины ребра, то уменьшаем его.

begin

D[x]:=D[v] + A[v,x];

P[x]:=v; //запоминаем откуда пришли

end;

end;

write('finis='); readln(t);

u:=t; write(u);

while u<>s do begin

u:=p[u]; write(' ',u);

end;

end;

begin

write('n=');

Readln(n);

for i:=1 to n do

for j:=i+1 to n do

begin

write('Rebro ',i,',',j,'= ');

12

Page 13: теория графов

readln(A[i,j]);

A[j,i]:=A[i,j];

end;

write('start='); readln(s);

Deisktr(a,n,s);

end.

13