Практика 6(СД)
.pdfgraph.Dijkstra(start); // запускаем алгоритм Дейкстры
}
}
// Класс Graph описывает граф через матрицу весов class Graph
{
private int[,] matrix; // матрица весов: matrix[i,j] — вес ребра из i в j (0 =
ребро отсутствует)
private int verticesCount; // число вершин графа
public Graph(int n) // конструктор класса Graph
{
verticesCount = n; matrix = new int[n, n];
// Инициализация матрицы нулями — пока ребер нет for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) matrix[i, j] = 0;
}
// Добавляет ориентированное ребро с весом
11
public void AddEdge(int from, int to, int weight = 1) // from — индекс начальной вершины ребра. to — индекс конечной вершины ребра. weight —
вес ребра
{
matrix [from, to] = weight;
}
// Генерирует случайный граф с заданным числом ребер и весами
public void RandomGraph(int maxWeight = 10)
{
Random rand = new Random();
Console.WriteLine("Введите количество ребер для случайного графа:");
int m = int.Parse(Console.ReadLine());
int added = 0;
while (added < m) // заполняем матрицу
{
int from = rand.Next(verticesCount);
int to = rand.Next(verticesCount);
if (from == to) continue; // Исключаем петли — ребра из вершины в саму себя
int weight = rand.Next(1, maxWeight + 1); // вес ребра от 1 до maxWeight
(10)
12
AddEdge(from, to, weight); added++;
}
}
// Выводит матрицу весов с подписями public void Display()
{
Console.Write("\t");
for (int j = 0; j < verticesCount; j++) Console.Write((char)('A' + j) + "\t"); // подписи столбцов
Console.WriteLine();
for (int i = 0; i < verticesCount; i++)
{
Console.Write((char)('A' + i) + "\t"); // подписи строк for (int j = 0; j < verticesCount; j++)
Console.Write(matrix[i, j] + "\t"); // веса ребер
Console.WriteLine();
}
}
13
// Реализация алгоритма Дейкстры, ищет минимальные расстояния из start
во все остальные вершины public void Dijkstra(int start)
{
const int INF = int.MaxValue; // бесконечность для инициализации int[] dist = new int[verticesCount]; // массив расстояний от start
bool[] visited = new bool[verticesCount]; // пометки посещенных вершин int[] prev = new int[verticesCount]; // массив для восстановления пути
for (int i = 0; i < verticesCount; i++) // изначальная установка данных
{
dist[i] = INF; // расстояния изначально бесконечны visited[i] = false; // вершины не посещены
prev[i] = -1; // предшественник не известен
}
dist[start] = 0; // расстояние от себя до себя равно 0
// Основной цикл. Графы, рёбра, начальная вершина(выбирает пользователь)
for (int count = 0; count < verticesCount - 1; count++) // На каждом шаге мы расширяем область известных кратчайших путей, постепенно находя минимальное расстояние до новых вершин.
{
14
int u = MinDistance(dist, visited); // выбираем непосещённую вершину с минимальной дистанцией
if (u == -1) break; // если таких нет, останавливаемся visited[u] = true; // отмечаем вершину посещённой
// Релаксация — пытаемся улучшить расстояния до соседей вершины
u
for (int v = 0; v < verticesCount; v++)
{
if (!visited[v] && matrix[u, v] > 0 && dist[u] != INF && dist[u] + matrix[u, v] < dist[v])
{
dist[v] = dist[u] + matrix[u, v]; prev[v] = u; // запоминаем путь
}
}
} // на выходе массив расстояний и массив предшественников
// Вывод результатов: кратчайшие расстояния и пути
Console.WriteLine($"Кратчайшие пути из вершины {(char)('A' + start)}:");
for (int i = 0; i < verticesCount; i++)
{
15
if (i == start) continue; // путь из вершины в себя не выводим if (dist[i] == INF)
Console.WriteLine($"{(char)('A' + start)} -> {(char)('A' + i)}: пути
нет");
else
{
Console.Write($"{(char)('A' + start)} -> {(char)('A' + i)} : {dist[i]} -
длина пути. Маршрут пути: ");
PrintPath(prev, i); // показывает маршрут
Console.WriteLine();
}
}
}
// Метод для нахождения вершины с минимальным dist среди непосещённых
private int MinDistance(int[] dist, bool[] visited)
{
int min = int.MaxValue; int minIndex = -1;
for (int v = 0; v < verticesCount; v++) // перебирает вершины
{
16
if (!visited[v] && dist[v] <= min) // проверка посещаемости и меньше ли найденного минимума
{
min = dist[v];
minIndex = v;
}
}
return minIndex;
}
// Рекурсивный вывод пути от start к вершине j
private void PrintPath(int[] prev, int j)
{
if (prev[j] == -1) // если предшественник вершины j не определён (равен -
1), значит, мы достигли начальной вершины.
{
Console.Write((char)('A' + j));
return;
}
PrintPath(prev, prev[j]);
Console.Write(" -> " + (char)('A' + j)); // происходит последовательный вывод пути от начальной вершины до текущей вершины с индексом j.
}
17
}
18
