Министерство науки и высшего образования Российской Федерации Федеральное государственное автономное образовательное учреждение высшего образования
«ТОМСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ СИСТЕМ УПРАВЛЕНИЯ И РАДИОЭЛЕКТРОНИКИ» (ТУСУР)
Кафедра комплексной информационной безопасности электронно-вычислительных систем (КИБЭВС)
ГРАФЫ Отчет по практической работе №6 по дисциплине «Структуры данных»
Студент гр.
________
__.__.2025
Принял
Преподаватель
кафедры КИБЭВС
________ Д.Р. Уразаев
__.__.2025
Задание
Реализовать возможность работы с графом N узлов, M ребер. Выберете самостоятельно структуру. Обеспечьте следующие интерфейсные методы:
ввод графа (можно случайным образом,можно вводить с клавиатуры) НЕДОПУСТИМО работать только с конечным числом ребер и узлов. Приложение должно позволять вводить разные графы.
вывод графа - матрица смежности или весов
Вариант 3. Задана система дорог. Определить кратчайшее расстояние из города А в город В, при этом путь не должен проходить через город С и D. Восстановить путь.
Оглавление
Задание 2
Введение 4
1 ХОД РАБОТЫ 5
Заключение 10
Приложение А 11
Введение
Целью работы является реализация программы для работы с графами, представляющими систему дорог с переменным числом узлов и рёбер. Программа позволяет вводить графы случайным образом или с клавиатуры и выводить матрицу смежности или весов. Основное внимание уделяется нахождению города с максимальной суммой кратчайших расстояний до остальных городов.
1 Ход работы
В работе реализуется ориентированный граф и матрица смежности.
Ориентированный граф — В ориентированном графе рёбра имеют направление, что означает, что если есть ребро от узла A к узлу B, то это не подразумевает наличие ребра от B к A.
Матрица
смежности
— это квадратная матрица, которая
используется для представления графа.
Если граф содержит N
узлов, матрица будет размером NxN.
Graph – инициализирует
граф с заданным количеством городов,
проверяет, чтобы количество городов
было больше нуля, создает матрицу
смежности, устанавливая расстояние
между городами на 0 для одного и того же
города и на очень большое значение для
всех остальных пар. (рис .1)
Р
исунок
1 — Graph
AddEdge
– добавляет
ребро между двумя городами с заданным
весом, проверяет корректность индексов
и положительность веса, устанавливает
расстояние в матрице смежности для
ориентированного графа (рис.
2)
Р
исунок
2 — AddEdge
PrintAdjMatrix — выводит матрицу смежности на экран (рис. 3)
Рисунок 3 — PrintAdjMatrix
FloydWarshall – реализует алгоритм Флойда-Уоршелла для нахождения кратчайших расстояний между всеми парами городов, создаёт новую матрицу расстояний, копируя данные из матрицы смежности и обновляя значения, если обнаруживаются более короткие пути через промежуточные города (рис. 4)
Р
исунок
4 — FloydWarshall
FindShortestPathWithAvoidance — предназначена для нахождения кратчайшего пути между двумя городами в ориентированном графе с исключением указанных городов из маршрута. (рис. 5)
Рисунок 5 — FindShortestPathWithAvoidance
Заключение
В ходе работы была успешно реализована программа для анализа графов дорожной сети. Выполнены задачи по вводу, выводу и поиску города с максимальными кратчайшими расстояниями. Это может быть полезным для оптимизации транспортных маршрутов.
Приложение а
(обязательное)
Код программы
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;
}
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 distance, List<int> path) FindShortestPathWithAvoidance(int start, int end, int[] avoidedCities)
{
// Проверка корректности входных данных
if (start < 0 || start >= numCities || end < 0 || end >= numCities)
throw new ArgumentException("Неверные начальный или конечный город");
if (avoidedCities == null)
avoidedCities = new int[0];
// Массивы для хранения расстояний и предков
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] && !avoidedCities.Contains(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] && !avoidedCities.Contains(v) &&
adjMatrix[u, v] != int.MaxValue / 2 &&
dist[u] + adjMatrix[u, v] < dist[v])
{
dist[v] = dist[u] + adjMatrix[u, v];
prev[v] = u;
}
}
}
// Восстанавливаем путь
List<int> path = new List<int>();
if (dist[end] != int.MaxValue / 2)
{
int current = end;
while (current != -1)
{
path.Add(current);
current = prev[current];
}
path.Reverse();
}
return (dist[end], path);
}
// Метод Флойда-Уоршелла для поиска всех кратчайших путей
public int[,] FloydWarshall()
{
int[,] dist = new int[numCities, numCities];
Array.Copy(adjMatrix, dist, numCities * numCities);
for (int k = 0; k < numCities; k++)
{
for (int i = 0; i < numCities; i++)
{
for (int j = 0; j < numCities; j++)
{
if (dist[i, k] != int.MaxValue / 2 && dist[k, j] != int.MaxValue / 2 &&
dist[i, j] > dist[i, k] + dist[k, j])
{
dist[i, j] = dist[i, k] + dist[k, j];
}
}
}
}
return dist;
}
class Program
{
static void Main(string[] args)
{
try
{
Console.Write("Сколько городов (узлов)? ");
int numCities = int.Parse(Console.ReadLine());
Graph graph = new Graph(numCities);
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;
}
catch (FormatException ex)
{
Console.WriteLine($"Ошибка формата: {ex.Message}. Повторите ввод.");
}
catch (ArgumentException ex)
{
Console.WriteLine($"Ошибка аргумента: {ex.Message}. Повторите ввод.");
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine($"Ошибка индекса: {ex.Message}. Повторите ввод.");
}
}
}
graph.PrintAdjMatrix();
// Поиск кратчайшего пути с исключением городов
Console.Write("Введите начальный город: ");
int start = int.Parse(Console.ReadLine());
Console.Write("Введите конечный город: ");
int end = int.Parse(Console.ReadLine());
Console.Write("Введите города для исключения (через запятую, Enter для пропуска): ");
string avoidInput = Console.ReadLine();
int[] avoidedCities;
if (string.IsNullOrWhiteSpace(avoidInput))
{
avoidedCities = new int[0];
}
else
{
avoidedCities = avoidInput
.Split(',')
.Select(s => s.Trim())
.Where(s => !string.IsNullOrEmpty(s))
.Select(int.Parse)
.ToArray();
}
var result = graph.FindShortestPathWithAvoidance(start, end, avoidedCities);
if (result.distance == int.MaxValue / 2)
{
Console.WriteLine("Путь не существует!");
}
else
{
Console.WriteLine($"Кратчайшее расстояние: {result.distance}");
Console.WriteLine($"Путь: {string.Join(" -> ", result.path)}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Произошла ошибка: {ex.Message}");
}
}
}
}
Томск 2025
