- •Лабораторная работа 3 (Вариант 15) Алгоритмы нахождения кратчайших путей на графах Лаб. Раб. №5, Часть 1, задание 1
- •Ответы на вопросы:
- •Какова теоретическая сложность алгоритмов, рассмотренных в настоящей лабораторной работе?
- •В решении каких прикладных задач используются алгоритмы определения в графе кратчайших расстояний между заданными вершинами?
- •Может ли быть применен рассмотренный алгоритм Дейкстры при определении кратчайшего расстояния в ориентированном графе?
- •Как работает алгоритм Дейкстры?
- •Как работает алгоритм динамического программирования в задачах определения в графе кратчайших расстояний между вершинами?
В решении каких прикладных задач используются алгоритмы определения в графе кратчайших расстояний между заданными вершинами?
1. Маршрутизация в компьютерных сетях: Алгоритмы определения кратчайших путей используются в сетевых протоколах, таких как OSPF (Open Shortest Path First) и IS-IS (Intermediate System to Intermediate System), для определения оптимальных маршрутов между сетевыми узлами.
2. Транспортная логистика: В логистике алгоритмы определения кратчайших путей используются для оптимизации маршрутов доставки грузов и определения оптимальных траекторий для транспортных средств.
3. Геоинформационные системы (ГИС): В ГИС алгоритмы определения кратчайших путей применяются для построения оптимальных маршрутов для навигации, планирования городского транспорта, анализа транспортной доступности и других задач.
4. Социальные сети: В социальных сетях алгоритмы определения кратчайших путей используются для поиска кратчайших связей между пользователями, оптимизации потока информации и рекламных кампаний.
5. Телекоммуникации: В телекоммуникационной отрасли алгоритмы определения кратчайших путей применяются для оптимизации маршрутизации вызовов, передачи данных и управления сетью.
Может ли быть применен рассмотренный алгоритм Дейкстры при определении кратчайшего расстояния в ориентированном графе?
Да, алгоритм Дейкстры может быть применен для определения кратчайшего расстояния в ориентированном графе, при условии, что все рёбра имеют неотрицательные веса. Однако, в случае наличия отрицательных весов на рёбрах, алгоритм Дейкстры может дать некорректный результат.
Это связано с тем, что алгоритм Дейкстры использует жадный подход к нахождению кратчайшего пути, и при наличии отрицательных весов он может "застрять" в цикле, не способный корректно обрабатывать такие ситуации.
Как работает алгоритм Дейкстры?
Сначала выбираем путь до начальной вершины равным нулю, и заносим эту вершину во множество уже выбранных, расстояние от которых до оставшихся невыбранных вершин определено. На каждом следующем этапе находим невыбранную вершину, расстояние до которой
наименьшее, соединенную ребром с какой-нибудь вершиной из множества выбранных (это расстояние будет равно расстоянию до уже выбранной вершины плюс длина ребра).
Как работает алгоритм динамического программирования в задачах определения в графе кратчайших расстояний между вершинами?
Метод рассматривает многостадийные процессы принятия решения. При постановке задачи динамического программирования формируется некоторый критерий. Процесс разбивается на стадии (шаги),в которых принимаются решения, приводящие к достижению общей цели. Таким образом, метод динамического программирования - метод
пошаговой оптимизации.
Введем функцию fi, определяющую минимальную длину пути из
начальной вершины в вершину i. Обозначим через Si j длину пути между вершинами i и j, а fj - наименьшую длину пути между вершиной j и
начальной вершиной. Выбирая в качестве i такую вершину, которая минимизирует сумму (Si j + fj), получаем уравнение:
fi = min {Si j + fj}.
Трудность решения данного уравнения заключается в том, что
неизвестная функция входит в обе части равенства. В такой ситуации
приходится прибегать к классическому методу последовательных приближений (итераций), используя рекуррентную формулу:
fi(k+1) = min {Si j + fj(k)},
где fj(k) - k-е приближение функции.
Возможен другой подход к решению поставленной задачи с помощью метода стратегий. При движении из начальной точки i в конечную
k получается приближение fi(0) = Sik, где Sik - длина пути между точками i
и k. Следующее приближение - поиск решения в классе двухзвенных
ломаных. Дальнейшие приближения ищутся в классе трехзвенных, четырехзвенных и других ломаных.
Код на C++:
#include <iostream>
#include <vector>
#include <climits>
#include <ctime>
#include <stack>
using namespace std;
//структура для представления ребра графа
struct Edge {
int target;
int weight;
Edge(int tgt, int w) : target(tgt), weight(w) {}
};
int findShortestPath(vector<vector<Edge>>& graph, int start, int end) {
int n = graph.size();
vector<int> dist(n, INT_MAX); //создание массива для хранения длин путей
dist[start] = 0; //начальная вершина имеет расстояние 0
vector<int> pred(n, -1); // Массив для хранения предшественников вершин в кратчайшем пути
for (int i = 0; i < 2; i++) {
//cout << "" << endl;
//cout << i << ":" << endl;
for (int u = 0; u < n; u++) {
//cout << u << ":" << endl;
for (Edge& e : graph[u]) {
int v = e.target;
int weight = e.weight;
//cout << v << ":" << weight <<endl;
if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
pred[v] = u;
//cout << "YES:" << dist[v] << endl;
}
}
}
}
for (int i = 0; i < n; i++){
cout << "f" << i + 1 << ": " << dist[i] << endl;
}
cout << "Путь: ";
stack<int> path;
int current = end;
while (current != -1) {
path.push(current);
current = pred[current];
}
while (!path.empty()) {
cout << path.top() + 1 << " ";
path.pop();
}
cout << endl;
return dist[end]; //возврат длины кратчайшего пути до конечной вершины
}
int main() {
int n = 7; //количество вершин в графе
vector<vector<Edge>> graph(n);
//добавление рёбер в граф
graph[0].push_back(Edge(1, 1));
graph[0].push_back(Edge(6, 20));
graph[0].push_back(Edge(4, 25));
graph[0].push_back(Edge(3, 8));
graph[1].push_back(Edge(2, 2));
graph[1].push_back(Edge(6, 15));
graph[2].push_back(Edge(5, 3));
graph[3].push_back(Edge(4, 9));
graph[4].push_back(Edge(6, 6));
graph[5].push_back(Edge(6, 4));
/*
graph[0].push_back(Edge(1, 3));
graph[0].push_back(Edge(2, 8));
graph[0].push_back(Edge(3, 4));
graph[1].push_back(Edge(5, 6));
graph[1].push_back(Edge(2, 4));
graph[2].push_back(Edge(5, 6));
graph[2].push_back(Edge(6, 8));
graph[2].push_back(Edge(4, 7));
graph[3].push_back(Edge(2, 10));
graph[3].push_back(Edge(4, 9));
graph[4].push_back(Edge(6, 2));
graph[5].push_back(Edge(6, 4));
*/
/*
graph[0].push_back(Edge(1, 6));
graph[0].push_back(Edge(4, 9));
graph[0].push_back(Edge(3, 7));
graph[1].push_back(Edge(5, 2));
graph[1].push_back(Edge(2, 5));
graph[2].push_back(Edge(3, 2));
graph[2].push_back(Edge(6, 3));
graph[3].push_back(Edge(6, 1));
graph[4].push_back(Edge(5, 4));
graph[4].push_back(Edge(6, 8));
graph[5].push_back(Edge(6, 4));
*/
int start = 1; //начальная вершина
int end = 7; //конечная вершина
start--;
end--;
clock_t startT = clock();
int shortestPath = findShortestPath(graph, start, end);
clock_t endT = clock();
if (shortestPath == INT_MAX){
cout << "Пути между вершинами не существует" << endl;
}
else{
cout << "Кратчайший путь от вершины " << start + 1 << " до вершины " << end + 1 << " равен " << shortestPath << endl;
}
double timeN = double(endT - startT) / CLOCKS_PER_SEC;
cout << "Время решения задачи: " << timeN << " секунд" << endl << endl;
return 0;
}
