Вы находитесь на странице: 1из 10

МИНОБРНАУКИ РОССИИ

САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ
ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
«ЛЭТИ» ИМ. В.И. УЛЬЯНОВА (ЛЕНИНА)
Кафедра информационной безопасности

ОТЧЕТ
по лабораторной работе №5
по дисциплине «Алгоритмы и структуры данных»
Тема: Нахождение кратчайшего пути в графе

Студент гр. 1363 Дао Н.Х.

Преподаватель Беляев А.В.

Санкт-Петербург
2022
Цель работы
Ознакомление с вариантами реализации алгоритмов на графах на примере
задачи поиска кратчайшего пути в неориентированном графе.
Теоретические сведения
Вершины графа в другую будет называться путь, имеющий
минимальную сумму весов ребер, входящих в него.
Задача поиска кратчайшего пути может быть сформулирована в виде:
 поиска кратчайшего пути между двумя конкретными вершинами;
 поиска кратчайших путей от заданной вершины до всех остальных
вершин графа;
 поиска кратчайших путей между всеми вершинами графа попарно.
Алгоритм Беллмана-Форда
Алгоритм использует метод динамического программирования и
формирует решение в виде квадратной матрицы, количество строк и столбцов
которой равно количеству вершин графа. Ячейка на пересечении строки “m” и
столбца “n” после окончания расчета содержит длину кратчайшего путь от
заданной вершины до вершины “m”, при условии, что он (путь) содержит не
более “n” ребер (считая номера столбцов с “0”).
Матрица заполняется по столбцам слева направо. Начальное заполнение
содержит нулевой столбец, где для строки заданной (исходной) вершины
установлено значение “0”, а для всех остальных строк – значение “∞” (на
практике используется достаточно большая по величине константа).
На каждой итерации цикла заполняется один столбец по следующему
алгоритму:
1) в заполняемый столбец копируются значения из предыдущего (соседнего
слева) столбца (в качестве базовых значений)
2) перебираются все ребра графа и, если данное ребро позволяет улучшить
(уменьшить) текущее значение в ячейке, соответствующей одному из
концов данного ребра, то значение в ней заменяется на улучшенное

2
Параллельно матрице длин кратчайших путей, описанной выше, можно
вести матрицу маршрутов, в которую в момент обновления значения в матрице
длин записывается номер вершины, из которой “пришел” улучшенный путь.
Алгоритм Дейкстры
Алгоритм последовательно анализирует (“обрабатывает”) все вершины
графа, начиная от заданной (исходной) следующим образом.
Изначально всем вершинам, кроме исходной, присваивается оценка
длины кратчайшего пути, равная “∞”, (исходной вершине присваивается оценка
“0”). Все вершины считаются “необработанными”.
В каждой итерации цикла среди необработанных вершин выбирается
одна, имеющая наименьшую на текущий момент оценку кратчайшего пути от
заданной (исходной). Анализируются все ребра, исходящие от нее в сторону
необработанных вершин, и если какое-либо из ребер улучшает (уменьшает)
текущую оценку, то эта оценка обновляется.

3
Теоретическая часть
Дан взвешенный связный неориентированный граф «Куб» (Вариант 7):

Поиска кратчайших путей от вершины A до всех остальных вершин.


1. Алгоритмом Беллмана-Форда.
A 0 0 0 0 0 0 0 0 -
B ∞ 16 16 16 16 16 16 16 A-B
C ∞ ∞ 13 13 13 13 13 13 A-D-C
D ∞ 2 2 2 2 2 2 2 A-D
E ∞ 5 5 5 5 5 5 5 A-E
F ∞ ∞ 17 17 17 17 17 17 A-E-F
G ∞ ∞ ∞ 34 34 34 34 34 A-E-F-G
H ∞ ∞ 17 17 17 17 17 17 A-D-H

2. Алгоритмом Дейкстры.
Обрабатываемая Оценка
вершина A B C D E F G H
- 0 ∞ ∞ ∞ ∞ ∞ ∞ ∞
A - 16, A ∞ 2, A 5, A ∞ ∞ ∞
D - 16, A 13, D - 5, A ∞ ∞ 17, D
E - 16, A 13, D - - 17, E ∞ 17, D
C - 16, A - - - 17, E 43, C 17, D
B - - - - - 17, E 43, C 17, D
F - - - - - - 34, F 17, D
4
H - - - - - - 34, F -
G - - - - - - - -
Кратчайший путь - A-B A-D- A-D A-E A-E- A-E- A-D-
C F F-G H

3. Сравнить результаты, получившиеся алгоритмами 1 и 2


Кратчайшие пути, получившиеся алгоритмами 1 и 2, совпадают.

5
Практическая часть
Реализовать поиск кратчайших путей по алгоритму Беллмана-Форда от
произвольной вершины (задается с клавиатуры) для графа, созданного по
алгоритму практической части лабораторной работы №4.
Алгоритм генерации исходного графа, содержащего 15 вершин.

Рис. 1 – Список всех ребер с их весами

6
Рис. 2 – Матрица длин кратчайших путей и список восстановленных
кратчайших путей до каждой из вершин

Выводы
В ходе работы мы изучили двух алгоритма нахождения на графах
кратчайших путей; написали програмы на языке C++ для нахождения
кратчайших путей на неориентированном графе по алгоритму Беллмана-
Форда.

7
Исходный код
#include <iostream>
#include <ctime>
#include <map>
#include <vector>

using namespace std;

typedef struct Edge {


int weight, u, v;
};
//генерация исходного графа
void Graph(int** edge, int n) {
map <int, bool> vis;
int num[105] = { 0 };
for (int i = 0; i < 35; i++) {
int k;
do {
k = rand() % 105;
} while (vis.find(k) != vis.end());
vis[k] = true;
num[k] = 1 + rand() % 50;
}
int k = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
edge[i][j] = num[k];
edge[j][i] = num[k];
if (edge[i][i + 1] == 0)
edge[i][i + 1] = 200;
if (edge[i][j] != 0)
cout << "Edge: " << i + 1 << "-" << j + 1 << " weight: " << edge[i][j] << endl;
k++;
}
}
cout << endl;
}
void BellmanFord(int** edge, int n, int s) {
vector <Edge> E; //массив ребер
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (edge[i][j] != 0) {
Edge e;
e.weight = edge[i][j];
e.u = i;
e.v = j;
E.push_back(e);
e.u = j;
e.v = i;
E.push_back(e);
}
}
}
int** D = new int* [n]; //матрица длин кратчайших путей
for (int i = 0; i < n; i++)
D[i] = new int[n];
for (int i = 0; i < n; i++) {
if (i == s) D[s][0] = 0;
else D[i][0] = 9999;
}
int* Pre = new int[n]; // предыдущая вершина
for (int i = 0; i < n; i++) {
Pre[i] = -1;
}
int k;
for (k = 1; k < n; k++) {
int count = 0;
for (int i = 0; i < n; i++) {
D[i][k] = D[i][k - 1];
}
for (int i = 0; i < E.size(); i++) {
int u = E[i].u;
int v = E[i].v;
int w = E[i].weight;
if (D[v][k] > D[u][k] + w) {
D[v][k] = D[u][k] + w;
Pre[v] = u;
count++;
}
}
if (count == 0) break;
}
cout << "Shortest path distance matrix:" << endl;
for (int i = 0; i < n; i++) {

9
for (int j = 0; j <= k; j++) {
cout << D[i][j] << "\t";
}
cout << endl;
}
for (int i = 0; i < n; i++) {
int u = i;
if (u != s) {
vector <int> path;
while (1) {
path.push_back(u);
if (Pre[u] == -1) break;
u = Pre[u];
}
for (int i = path.size() - 1; i >= 0; i--) {
if (i == 0) {
cout << path[0] + 1;
break;
}
cout << path[i] + 1 << "(" << edge[path[i]][path[i - 1]] << ")";
}
cout << endl;
}
}
}

int main() {
int n = 15;
int** edge = new int* [n];
for (int i = 0; i < n; i++)
edge[i] = new int[n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
edge[i][j] = 0;
srand(time(NULL));
Graph(edge, n);
int s;
cout << "Enter start vertex: ";
cin >> s;
BellmanFord(edge, n, s - 1);
delete[] edge;
return 0;
}

10

Вам также может понравиться