Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Дискретная математика в программировании. Практикум. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
12.08.2026
Размер:
1 Мб
Скачать

Г-11)

Ø

Г-12)

х1, х4, х5

Г-13)

х2

Г-14)

х3, х5

Г-15)

х1

 

 

Г-21)

Ø

Г-22)

х1, х3, х5

Г-23)

х1, х4, х5

Г-24)

х1, х2

Г-25)

Ø

ρs 1)

2

ρs 2)

1

ρs 3)

1

ρs 4)

1

ρs 5)

2

 

 

ρt 1)

0

ρt 2)

3

ρt 3)

1

ρt 4)

2

ρt 5)

1

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

Вершины просматриваются в порядке возрастания их расстояния от корня. Алгоритм прекращает свою работу после обхода всех вершин графа, либо в случае выполнения требуемого условия (например, найти кратчайший путь из вершины1 в вершину 6).

Каждая вершина может находиться в одном из 3 состояний:

0— необнаруженная вершина;

1— обнаруженная, но не посещенная вершина;

2— обработанная вершина.

Применение алгоритма поиска в ширину.

1.Поиск кратчайшего пути в невзвешенном графе (ориентированном или неориентированном).

2.Поиск компонент связности.

3.Нахождение решения какой-либо задачи( гры) с наименьшим числом ходов.

4.Нахождение всех рёбер, лежащих на каком-либо кратчайшем пути между заданной парой вершин.

41

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

Алгоритм поиска в ширину работает как ориентированных, так и на неориентированных графах.

Для реализации алгоритма удобно использовать очередь: #include <iostream>

#include <queue> // очередь using namespace std;

int main()

{

queue<int> Queue;

int mas[7][7] = { { 0, 1, 1, 0, 0, 0, 1 }, // матрица смежности

{1, 0, 1, 1, 0, 0, 0 },

{1, 1, 0, 0, 0, 0, 0 },

{0, 1, 0, 0, 1, 0, 0 },

{0, 0, 0, 1, 0, 1, 0 },

{0, 0, 0, 0, 1, 0, 1 },

{1, 0, 0, 0, 0, 1, 0 } };

int nodes[7]; // вершины графа for (int i = 0; i < 7; i++)

nodes[i] = 0; // исходно все вершины равны 0 Queue.push(0); // помещаем в очередь первую вершину while (!Queue.empty())

{ // пока очередь не пуста

int node = Queue.front(); // извлекаем вершину Queue.pop();

nodes[node] = 2; // отмечаем ее как посещенную for (int j = 0; j < 7; j++)

{// проверяем для нее все смежные вершины if (mas[node][j] == 1 && nodes[j] == 0)

{ // если вершина смежная и не обнаружена

Queue.push(j); // добавляем ее в очередь

nodes[j] = 1; // отмечаем вершину как

обнаруженную

}

}

cout << node + 1 << endl; // выводим номер вершины

}

cin.get(); return 0;

}

42

Поиск в глубину– это алгоритм обхода вершин графа. Поиск в ширину производится симметрично(вершины графа просматривались по уровням). Поиск в глубину предполагает продвижение вглубь до тех, покапор это возможно. Невозможность продвижения означает, что следующим шагом будет переход на последний, имеющий несколько вариантов движения (один из которых исследован полностью), ранее посещенный узел (вершина).

Отсутствие последнего свидетельствует об одной из двух возможных ситуаций:

-все вершины графа уже просмотрены;

-просмотрены вершины доступные из вершины, взятой в качестве начальной, но не все(несвязные и ориентированные графы допускают последний вариант).

Каждая вершина может находиться в одном из 3 состояний: 0 – необнаруженная вершина; 1 – обнаруженная, но не посещенная вершина; 2 – обработанная вершина;

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

1.Поиск любого пути в графе.

2.Поиск лексикографически первого пути в графе.

3.Проверка, является ли одна вершина дерева предком

другой.

4.Поиск наименьшего общего предка.

5.Топологическая сортировка.

6.Поиск компонент связности.

Алгоритм

поиска

 

в

глубину

работает

как

ориентированных,

так

и

на

неориентированных

. графах

Применимость алгоритма зависит от конкретной задачи. Для реализации алгоритма удобно использовать стек или рекурсию:

43

#include <iostream> #include <stack> // стек using namespace std; int main()

{

stack<int> Stack;

int mas[7][7] = { { 0, 1, 1, 0, 0, 0, 1 }, // матрица смежности

{1, 0, 1, 1, 0, 0, 0 },

{1, 1, 0, 0, 0, 0, 0 },

{0, 1, 0, 0, 1, 0, 0 },

{0, 0, 0, 1, 0, 1, 0 },

{0, 0, 0, 0, 1, 0, 1 },

{1, 0, 0, 0, 0, 1, 0 } };

int nodes[7]; // вершины графа

for (int i = 0; i < 7; i++) // исходно все вершины равны 0 nodes[i] = 0;

Stack.push(0); // помещаем в очередь первую вершину while (!Stack.empty())

{ // пока стек не пуст

int node = Stack.top(); // извлекаем вершину Stack.pop();

if (nodes[node] == 2) continue;

nodes[node] = 2; // отмечаем ее как посещенную for (int j = 6; j >= 0; j--)

{// проверяем для нее все смежные вершины if (mas[node][j] == 1 && nodes[j] != 2)

{// если вершина смежная и не обнаружена

Stack.push(j); // добавляем ее в cтек

nodes[j] = 1; // отмечаем вершину как

обнаруженную

}

}

cout << node + 1 << endl; // выводим номер вершины

}

cin.get(); return 0;

}

44

Задание

1. Для заданного графа написать программу построения

матрицы смежности и вычисления характеристик: Г(хi), Г-1i),

Г2i), Г-2i), ρsi), ρti):

2. Для графа задания 1 написать программу:

- если цифра вариатра задания четная– для

просмотра

графа

в ширину;

 

 

- если цифра вариатра задания нечетная– для

просмотра

графа

в глубину.

 

 

45

Практическая работа № 9.

Кратчайший путь в орграфе. Построение кратчайшего остовного дерева, Гамильтонова цикла

Цель работы:

приобрести навыки

построения

кратчайшего

 

пути в графе, построения остовного дерева графа,

также

 

построения Гамильтонова цикла в графе.

 

 

 

 

 

 

 

Теоретические сведения

 

 

 

 

 

Построение

кратчайшего

пути

в .графеДугам

во

 

взвешенном орграфе поставлено в соответствие некоторое число

 

(вес). Это может быть евклидово расстояние между вершинами

 

или какая-либо другая числовая характеристика(цена, время,

 

энергия). Ставится задача нахождения кратчайшего пути во

 

взвешенном орграфе от одной заданной

вершины

до

другой.

 

Длина пути — сумма весов дуг пути. Вес дуг может быть

 

положительным, отрицательным, нулевым или бесконечным (что

 

соответствует отсутствию дуги).

 

 

 

 

 

 

 

Для поиска кратчайшего пути применяется

алгоритм

Дейкстры.

Пошаговый

алгоритм

определения

кратчайшего

 

расстояния от вершины A до B состоит в следующем. С каждой

 

вершиной связывается метка. Метка может быть постоянной или

 

временной.

Первоначально

вершине A

приписывается

 

постоянная метка 0, а всем остальным метка ∞. На первом шаге

 

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

 

всех остальных вершин. Если некоторая вершина не соединена с

 

вершиной с постоянной меткой или дуга направлена в обратную

 

сторону, то расстояние принимается бесконечным. Найденные

 

расстояния

 

являются

временными

 

метками .

верш

Минимальная из временных меток берется за постоянную. На

 

следующем шаге временные метки всех вершин(кроме тех, у

 

которых постоянные метки) вычисляются как сумма значения

 

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

 

случае, если это значение не больше предыдущего значения

 

временной метки данной вершины. Таким образом, временная

 

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

 

Минимальная

из

временных

меток

всех

вершин

опять

46

принимается за постоянную. Процесс продолжается до тех пор, пока вершина B не получит постоянную метку. Значение этой метки и есть кратчайшее расстояние от A до B.

Пример. Найти кратчайший путь отвершины А до вершины В в заданнос графе

Решение.

1.Вершина A получает постоянную метку 0, остальные — метку ∞:

2.Вычисляем расстояния от вершины1 с постоянной меткой 0. Вершины 2, 4 и 5 меняют свои временные метки на 11,

12и 26. Остальные имеют прежние метки— ∞. Очевидно, наименьшей меткой является 11. Она и становится постоянной:

3.Вычисляем расстояния от вершины2 с постоянной меткой 11. Вершины 3 и 5 имеют расстояния 15 и 16 до вершины

2.Суммируя, получаем значения 26 и 27. Для вершины 5 прежнее значение, 26, было меньше нового значения27. Следовательно, значение метки 5 не меняем; оно остается равным26. Из трех временных меток — 12, 26 и 26 — наименьшая принадлежит вершине 4. Эта метка и становится постоянной:

47

4.

Вычисляем

расстояния

от

вершины4 с

постоянной

меткой 12. Вершина 5 имеет до

нее

расстояние13.

Суммируя

(13+12),

получаем

значение 25

временной метки

вершины5

вместо прежнего значения 26. Из двух временных меток вершин 3 и 5 наименьшая принадлежит вершине 5. Эта метка и становится постоянной:

5.На следующем этапе, вычисляя расстояния от вершины 5

спостоянной меткой 25, приходим к конечной вершине B. Но ее метка (25+14 = 39) не становится постоянной, т.к. она не является минимальной. Расстояние от вершины 5 до вершины 3 принято ∞

(они

не соединены).

Прежнее значение временной метки

вершины 3 меньше ∞. Поэтому метка вершины 3 не меняется.

Метка

вершины 3 со

значением 26, меньшим 39, становится

постоянной. На следующем этапе ищем расстояния от нее:

6. Расстояние от вершины 3 до вершины 6 составляет 20. Так как 26 + 20 > 39, значение метки 6 не меняем. На этом шаге

она остается прежней и единственной временной . меткой Временная метка вершины6 становится постоянной, что означает конец процесса. Минимальное расстояние отA до B

равно 39.

48

Построение

кратчайшего

остовного

 

дерева. Деревом

 

называется связный граф, не содержащий циклов. Ориентиро-

 

ванным

деревом называется

орграф

без

циклов,

в

котором

 

имеется

вершина

0, х из

которой

существует

только

один

 

ориентированный путь в любую другую вершину. Деревом графа

 

G называется любой его связный ациклический подграф. Дерево

 

графа G, содержащее все вершины этого графа, называется ос-

 

товным деревом (остовом)

Т

графа

G. Остов

существует

в

 

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

 

не единственным способом.

 

 

 

 

 

 

 

 

 

 

 

Кратчайшим

 

остовом

взвешенного

 

графаG

будем

 

называть остов, у которого сумма весов всех ребер наименьшая.

 

Для

построения

 

кратчайшего

 

остова

 

графа

используются

алгоритмы Краскала и Прима.

 

 

 

 

 

 

 

 

 

 

 

Алгоритм

 

Краскала заключается

в

следующем. На

 

начальном этапе из всех ребер графа G выбирается ребро u1

 

минимального

веса

и

 

включается

 

в .

Наостов каждом

 

последующем i-м шаге из еще не включенных в остов ребер

 

выбирается

ребро,

имеющее

минимальный

 

вес

и

не

составляющее циклов с уже выбранными ребрами. Процесс

 

продолжается до тех пор, пока в остов не будет включеноn-1

 

ребро.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Алгоритм Прима отличается от алгоритма Краскала только

 

тем, что на каждом этапе строится не просто ациклический граф,

 

а дерево, которое в дальнейшем последовательно разрастается.

 

При этом если дерево Tj

уже построено, то новое ребро

 

выбирается не из всех оставшихся ребер графа G, а только из тех,

 

которые соединяют вершины дереваTj

с

вершинами, не

 

включенными

в Tj.

Из

этих

ребер

выбирается

ребро

 

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

49

Пример. С использованием алгоритмов Краскала и Прима построить кратчайший остов для графа:

В таблицах приводится последовательность выбора ребер остовного дерева с использованием алгоритмов Краскала и Прима.

Алгоритм Краскала

Шаг

Ребро

Вес

1

x6,x7

3

2

x1,x2

5

3

x3,x4

7

4

x1,x3

8

5

x3,x6

9

6

x11,x13

10

7

x6,x9

11

8

x6,x10

12

9

x3,x11

13

10

x8,x9

14

11

x12,x13

15

12

x4,x5

18

Алгоритм Прима

Шаг

Ребро Вес

1

x6,x7

3

2

x3,x6

9

3

x3,x4

7

4

x1,x3

8

5

x1,x5

5

6

x6,x9

11

7

x6,x10

12

8

x3,x11

13

9

x11,x13

10

10

x8,x9

14

11

x12,x13

15

12

x4,x5

18

Кратчайший остов для данного графа имеет следующий вид:

50

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]