Министерство науки и высшего образования Российской Федерации Федеральное государственное автономное образовательное учреждение высшего образования
«ТОМСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ СИСТЕМ УПРАВЛЕНИЯ И РАДИОЭЛЕКТРОНИКИ» (ТУСУР)
Кафедра безопасности информационных систем (БИС)
ГРАФЫ Отчет по практической работе №6 по дисциплине «Структуры данных»
Студент гр.
________
__.__.2025
Принял
Преподаватель
кафедры КИБЭВС
________ Е.Е. Лунева
__.__.2025
Задание
Реализовать возможность работы с графом N узлов, M ребер. Выберете самостоятельно структуру. Обеспечьте следующие интерфейсные методы:
ввод графа (можно случайным образом,можно вводить с клавиатуры) НЕДОПУСТИМО работать только с конечным числом ребер и узлов. Приложение должно позволять вводить разные графы.
вывод графа - матрица смежности или весов
Вариант 1. Задана система дорог. Определить кратчайшие пути из одного города (задавать из какого) ко всем другим. Восстановить путь.
Оглавление
Задание 2
Введение 4
1 ХОД РАБОТЫ 5
Заключение 9
Приложение А 10
Введение
Целью работы является реализация программы для работы с графами, представляющими систему дорог с переменным числом узлов и рёбер. Программа позволяет вводить графы случайным образом или с клавиатуры и выводить матрицу смежности или весов. Основное внимание уделяется нахождению города с максимальной суммой кратчайших расстояний до остальных городов.
1 Ход работы
В работе реализуется ориентированный граф и матрица смежности.
Ориентированный граф — В ориентированном графе рёбра имеют направление, что означает, что если есть ребро от узла A к узлу B, то это не подразумевает наличие ребра от B к A.
Матрица
смежности
— это квадратная матрица, которая
используется для представления графа.
Если граф содержит N
узлов, матрица будет размером NxN.
Graph – инициализирует
граф с заданным количеством городов,
проверяет, чтобы количество городов
было больше нуля, создает матрицу
смежности, устанавливая расстояние
между городами на 0 для одного и того же
города и на очень большое значение для
всех остальных пар. (рис .1)
Рисунок
1 — Graph
AddEdge
– добавляет
двустороннюю дорогу между двумя городами
с указанным расстоянием.
(рис. 2)
Р
исунок
2 — AddEdge
PrintAdjMatrix
— выводит матрицу смежности на экран.
(рис. 3)
Рисунок 3 — PrintAdjMatrix
ReconstructPath -
Восстанавливает конкретный маршрут
между двумя городами на основе результатов
алгоритма Дейкстры.
(рис. 4)
Р
исунок
4 — ReconstructPath
PrintAllShortestPaths -
Отображает все кратчайшие пути из
заданного города с расстояниями и
полными маршрутами.
(рис. 5)
Р
исунок
5 — PrintAllShortestPaths
Заключение
В ходе работы была реализована программа для работы с графами дорожных сетей, включающая функционал автоматической генерации случайных графов и ручного ввода данных, а также алгоритм Дейкстры для нахождения кратчайших путей из заданного города ко всем остальным с возможностью восстановления конкретных маршрутов.
Приложение а
(обязательное)
Код программы
using System;
using System.Collections.Generic;
using System.Linq;
class Graph
{
private int[,] adjMatrix;
private int numCities;
public Graph(int numCities)
{
if (numCities <= 0)
{
throw new ArgumentException("Количество городов должно быть больше нуля.");
}
this.numCities = numCities;
adjMatrix = new int[numCities, numCities];
// Инициализация матрицы смежности
for (int i = 0; i < numCities; i++)
{
for (int j = 0; j < numCities; j++)
{
if (i == j)
adjMatrix[i, j] = 0;
else
adjMatrix[i, j] = int.MaxValue / 2;
}
}
}
// Добавление ребра
public void AddEdge(int u, int v, int weight)
{
if (u >= numCities || v >= numCities || u < 0 || v < 0)
{
throw new IndexOutOfRangeException("Ошибка! Указанный город не существует.");
}
if (weight <= 0)
{
throw new ArgumentException("Расстояние между городами должно быть положительным числом.");
}
adjMatrix[u, v] = weight;
adjMatrix[v, u] = weight;
}
// Автоматическая генерация графа
public void GenerateRandomGraph(int maxEdges, int maxWeight = 100)
{
Random rand = new Random();
int edgesAdded = 0;
// Гарантируем связность графа
for (int i = 1; i < numCities; i++)
{
int weight = rand.Next(1, maxWeight + 1);
AddEdge(i - 1, i, weight);
edgesAdded++;
}
// Добавляем случайные рёбра
while (edgesAdded < maxEdges && edgesAdded < numCities * (numCities - 1) / 2)
{
int u = rand.Next(0, numCities);
int v = rand.Next(0, numCities);
int weight = rand.Next(1, maxWeight + 1);
if (u != v && adjMatrix[u, v] == int.MaxValue / 2)
{
AddEdge(u, v, weight);
edgesAdded++;
}
}
}
// Вывод матрицы смежности
public void PrintAdjMatrix()
{
Console.WriteLine("Матрица смежности:");
Console.Write(" ");
for (int i = 0; i < numCities; i++)
{
Console.Write($"{i}\t");
}
Console.WriteLine();
for (int i = 0; i < numCities; i++)
{
Console.Write($"{i}: ");
for (int j = 0; j < numCities; j++)
{
if (adjMatrix[i, j] == int.MaxValue / 2)
Console.Write("INF\t");
else
Console.Write(adjMatrix[i, j] + "\t");
}
Console.WriteLine();
}
}
// Алгоритм Дейкстры для поиска кратчайших путей из одного города ко всем другим
public (int[] distances, int[] predecessors) Dijkstra(int start)
{
if (start < 0 || start >= numCities)
throw new ArgumentException("Неверный начальный город");
int[] dist = new int[numCities];
int[] prev = new int[numCities];
bool[] visited = new bool[numCities];
// Инициализация
for (int i = 0; i < numCities; i++)
{
dist[i] = int.MaxValue / 2;
prev[i] = -1;
}
dist[start] = 0;
// Основной цикл алгоритма Дейкстры
for (int count = 0; count < numCities - 1; count++)
{
// Находим вершину с минимальным расстоянием
int u = -1;
int minDist = int.MaxValue / 2;
for (int i = 0; i < numCities; i++)
{
if (!visited[i] && dist[i] < minDist)
{
minDist = dist[i];
u = i;
}
}
if (u == -1) break;
visited[u] = true;
// Обновляем расстояния до соседей
for (int v = 0; v < numCities; v++)
{
if (!visited[v] && adjMatrix[u, v] != int.MaxValue / 2 &&
dist[u] + adjMatrix[u, v] < dist[v])
{
dist[v] = dist[u] + adjMatrix[u, v];
prev[v] = u;
}
}
}
return (dist, prev);
}
// Восстановление пути от start до end
public List<int> ReconstructPath(int start, int end, int[] predecessors)
{
List<int> path = new List<int>();
if (predecessors[end] == -1 && start != end)
return path; // Путь не существует
int current = end;
while (current != -1)
{
path.Add(current);
current = predecessors[current];
}
path.Reverse();
// Проверяем, что путь действительно начинается с start
if (path.Count > 0 && path[0] == start)
return path;
else
return new List<int>();
}
// Вывод всех кратчайших путей из заданного города
public void PrintAllShortestPaths(int start)
{
var (distances, predecessors) = Dijkstra(start);
Console.WriteLine($"\nКратчайшие пути из города {start}:");
Console.WriteLine("Город | Расстояние | Путь");
Console.WriteLine("---------------------------");
for (int i = 0; i < numCities; i++)
{
if (i == start) continue;
if (distances[i] == int.MaxValue / 2)
{
Console.WriteLine($"{i} | Нет пути | -");
}
else
{
List<int> path = ReconstructPath(start, i, predecessors);
string pathStr = path.Count > 0 ? string.Join(" -> ", path) : "Нет пути";
Console.WriteLine($"{i} | {distances[i],-10} | {pathStr}");
}
}
}
}
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("=== ГЕНЕРАТОР СЛУЧАЙНЫХ ГРАФОВ ===");
// Ввод количества городов
Console.Write("Введите количество городов: ");
int numCities = int.Parse(Console.ReadLine());
Graph graph = new Graph(numCities);
Console.WriteLine("\nВыберите способ создания графа:");
Console.WriteLine("1 - Автоматическая генерация");
Console.WriteLine("2 - Ручной ввод");
Console.Write("Ваш выбор: ");
int choice = int.Parse(Console.ReadLine());
if (choice == 1)
{
// Автоматическая генерация
Console.Write("Введите максимальное количество дорог: ");
int maxEdges = int.Parse(Console.ReadLine());
Console.Write("Введите максимальную длину дороги (по умолчанию 100): ");
string maxWeightInput = Console.ReadLine();
int maxWeight = string.IsNullOrEmpty(maxWeightInput) ? 100 : int.Parse(maxWeightInput);
graph.GenerateRandomGraph(maxEdges, maxWeight);
Console.WriteLine("Граф успешно сгенерирован!");
}
else if (choice == 2)
{
// Ручной ввод
Console.Write("Сколько дорог добавить? ");
int numRoads = int.Parse(Console.ReadLine());
for (int i = 1; i <= numRoads; i++)
{
bool running = true;
while (running)
{
try
{
Console.WriteLine($"Дорога {i}: введите начальный город, конечный город и расстояние в формате X,Y,Z");
string input = Console.ReadLine();
string[] parts = input.Split(',');
if (parts.Length != 3)
{
throw new FormatException("Неверный формат ввода. Используйте формат X,Y,Z.");
}
int u = int.Parse(parts[0]);
int v = int.Parse(parts[1]);
int weight = int.Parse(parts[2]);
graph.AddEdge(u, v, weight);
running = false;
Console.WriteLine($"Дорога {u}-{v} длиной {weight} добавлена.");
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка: {ex.Message}. Повторите ввод.");
}
}
}
}
else
{
Console.WriteLine("Неверный выбор.");
return;
}
// Вывод матрицы смежности
Console.WriteLine("\n" + new string('=', 50));
graph.PrintAdjMatrix();
// Поиск кратчайших путей
Console.WriteLine("\n" + new string('=', 50));
Console.Write("Введите начальный город для поиска кратчайших путей: ");
int startCity = int.Parse(Console.ReadLine());
graph.PrintAllShortestPaths(startCity);
}
catch (Exception ex)
{
Console.WriteLine($"Произошла ошибка: {ex.Message}");
}
Console.WriteLine("\nНажмите любую клавишу для выхода...");
Console.ReadKey();
}
}
Томск 2025
