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

Практика 6(СД)

.docx
Скачиваний:
0
Добавлен:
08.10.2025
Размер:
496.96 Кб
Скачать

Министерство науки и высшего образования Российской Федерации

Федеральное государственное автономное образовательное учреждение

высшего образования

ТОМСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ СИСТЕМ

УПРАВЛЕНИЯ И РАДИОЭЛЕКТРОНИКИ (ТУСУР)

Кафедра комплексной информационной безопасности электронно-вычислительных систем (КИБЭВС)

ГРАФЫ

Отчёт по практической работе №6

по дисциплине «Структуры данных»

Студент гр. 714-1

_______ И.С. Максимов

__.__.2025

Доцент кафедры КИБЭВС

_______ Е.Е. Лунёва

__.__.2025

Томск 2025

Оглавление

Введение 3

Заключение 9

Введение

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

  1. Ход работы

Была создана основная точка входа в программу, реализующую работу с графом и алгоритм Дейстры.

На рисунке 1.1 представлен фрагмент код.

Рисунок 1.1 – Основная точка входа в программу

Реализованный класс Graph. Часть кода, представленная на рисунке 1.2 описывает класс и его конструктор, который создаёт граф с заданным числом вершин.

Рисунок 1.2 – Реализованный класс Graph

AddEdge: добавляет ориентированное ребро с весом.

На рисунке 1.3 представлен фрагмент кода.

Рисунок 1.3 – Метод AddEdge

RandomGraph: генерирует случайный граф с заданным числом ребер и весами.

На рисунке 1.4 представлен фрагмент кода.

Рисунок 1.4 – метод RandomGraph

Метод Display: выводит матрицу весов с подписями.

На рисунке 1.5 представлен фрагмент кода.

Рисунок 1.5 – метод Display

Метод Dijkstra: ищет минимальные расстояния из start во все остальные вершины.

На рисунках 1.6 и 1.7 представлен фрагмент кода.

Рисунок 1.6 – Начало реализации метода Dijkstra

Рисунок 1.7 – Основной цикл метода Dijkstra

Метод MinDistance: служит для нахождения вершины с минимальным dist среди не посещённых.

На рисунках 1.8 представлен фрагмент кода.

Рисунок 1.8 – Метод MinDistance

Метод PrintPath: строит и выводит полный маршрут от стартовой вершины до j в правильном порядке.

На рисунках 1.9 представлен фрагмент кода.

Рисунок 1.9 – Метод PrintPath

Заключение

В ходе работы была успешно реализована программа для анализа графов дорожной сети. Выполнены задачи по вводу, выводу и поиску города с максимальными кратчайшими расстояниями. Это может быть полезным для оптимизации транспортных маршрутов.

Приложение А

Листинг кода:

// Класс программы с точкой входа

class Program

{

static void Main()

{

Console.WriteLine("Введите количество узлов в графе:");

int n = int.Parse(Console.ReadLine()); // ввод количества вершин

Graph graph = new Graph(n); // создаём граф

graph.RandomGraph(); // случайно генерируем ребра (без петель)

graph.Display(); // выводим матрицу смежности

Console.WriteLine($"Введите начальный узел для поиска кратчайших путей (от A до {(char)('A' + n - 1)}):");

char startChar = Char.ToUpper(Console.ReadKey().KeyChar); // строка считывает с клавиатуры одну нажатую клавишу, превращает её в заглавный символ и сохраняет в startChar

Console.WriteLine();

int start = startChar - 'A'; // преобразуем букву в индекс

graph.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;

}

// Добавляет ориентированное ребро с весом

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)

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();

}

}

// Реализация алгоритма Дейкстры, ищет минимальные расстояния из 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++) // На каждом шаге мы расширяем область известных кратчайших путей, постепенно находя минимальное расстояние до новых вершин.

{

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++)

{

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++) // перебирает вершины

{

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.

}

}

Соседние файлы в предмете Структуры данных