using System.Diagnostics; using System.Text.Json; using AntColony.Algorithm; namespace AntColony; class Program { /// /// Путь до файла с ребрами /// Файл представлен в формате JSON вместо TSV /// Файл содержит заголовок /// Количество итераций /// Скорость испарения феромонов public static void Main(FileInfo file, bool json = false, bool hasHeader = false, int iterations = 100, double evaporationRate = 0.1) { Console.Write("Чтение файла..."); var sw = new Stopwatch(); sw.Start(); double[][] distances = json ? ParseEdgeJsonAsync(file.FullName).Result! : ParseEdgeFile(file.FullName, hasHeader); Console.WriteLine($"\rСчитано {distances.Length} вершин за {sw.Elapsed} ({sw.ElapsedMilliseconds} мс).\n"); var aco = new AntColonyOptimizer(distances: distances, evaporationRate: evaporationRate) .AddAnts(10, 1, 2, 100) // 10 муравьев, для которых расстояние в 2 раза важнее феромонов .AddAnts(10, 1, 1, 100) // 10 муравьев, для которых расстояние столь же важно, сколько феромоны .AddAnts(10, 1, 5, 200) // 10 муравьев, для которых расстояние в 5 раз важнее феромонов, и которые оставляют в 2 раза больше феромонов .CompileAnts(shuffle: true); // перемешиваем муравьев. По надобности можно оставить в исходном порядке sw.Reset(); Console.CancelKeyPress += (e, f) => { var (tour, distance) = aco.EarlyExit(); Console.WriteLine("\n\n" + new string('-', Console.BufferWidth)); Console.CursorLeft = 0; Console.WriteLine($"\nРанняя остановка. Время работы: {sw.Elapsed}\n"); if (tour.Count == 0) Console.WriteLine("Путь не найден."); else Console.WriteLine($"Лучший путь (длина {distance}):\n[ {string.Join(", ", tour)} ]"); }; sw.Start(); var (bestTour, bestDistance) = aco.Solve(iterations); Console.WriteLine(new string('-', Console.BufferWidth)); Console.WriteLine($"Задача решена за {sw.Elapsed} ({sw.ElapsedMilliseconds} мс)."); if (bestTour.Count == 0) { Console.WriteLine("Гамильтонов цикл не найден."); return; } Console.WriteLine($"Лучший путь:\n[ {string.Join(", ", bestTour)} ]"); Console.WriteLine($"Длина: {bestDistance}."); } private static async Task ParseEdgeJsonAsync(string filePath) { using var s = File.OpenRead(filePath); return await JsonSerializer.DeserializeAsync(s); } private static double[][] ParseEdgeFile(string filePath, bool skipHeader) { List lines = [.. File.ReadAllLines(filePath)]; if (skipHeader) lines.RemoveAt(0); HashSet vertices = []; int maxVertex = 0; foreach (string line in lines) { string[] parts = line.Split(); if (parts.Length != 3) continue; if (int.TryParse(parts[0], out int v1)) vertices.Add(v1); if (int.TryParse(parts[1], out int v2)) vertices.Add(v2); maxVertex = int.Max(maxVertex, v1); maxVertex = int.Max(maxVertex, v2); } double[][] adjacencyMatrix = new double[maxVertex + 1][]; for (int i = 0; i < maxVertex + 1; i++) { adjacencyMatrix[i] = new double[maxVertex + 1]; for (int j = 0; j < maxVertex + 1; j++) { adjacencyMatrix[i][j] = 0.0; } } foreach (string line in lines) { string[] parts = line.Split(); if (parts.Length != 3) continue; if (int.TryParse(parts[0], out int v1) && int.TryParse(parts[1], out int v2) && double.TryParse(parts[2], out double distance)) { adjacencyMatrix[v1][v2] = distance; adjacencyMatrix[v2][v1] = distance; } } return adjacencyMatrix; } }