Практики(Вариант №7) / Практическая работа №6
.pdfПриложение А
(обязательное) Код программы
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; |
|
|
|
} |
elseadjMatrix[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++)
{
11
|
|
Console.Write($"{i}: "); |
|
|
|
for (int j = 0; j < numCities; j++) |
|
|
|
{ |
if (adjMatrix[i, j] == int.MaxValue / 2) |
|
|
|
|
|
|
|
Console.Write("INF\t"); |
|
|
} |
elseConsole.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; |
|
= 0; |
|
dist[start] |
||
// Основной цикл алгоритма Дейкстры |
|||
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; |
|
} |
|
|
|
|
|
|
12
}
// Восстанавливаем путь 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(); |
13
|
|
|
|
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(); |
|||
|
|
|
|
|
||
avoidedCities); var result = graph.FindShortestPathWithAvoidance(start, end, |
||||||
|
if (result.distance == int.MaxValue / 2) |
|||||
|
{ |
Console.WriteLine("Путь не существует!"); |
||||
|
} |
|||||
|
|
|
|
|
||
|
else |
|
|
|
|
|
14
|
{ |
Console.WriteLine($"Кратчайшее расстояние: {result.distance}"); |
|
|
|
|
} |
Console.WriteLine($"Путь: {string.Join(" -> ", result.path)}"); |
} |
|
|
|
|
|
catch (Exception ex) |
||
{Console.WriteLine($"Произошла ошибка: {ex.Message}");
}} } }
15
