Program.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. using System.Diagnostics;
  2. using System.Text.Json;
  3. using AntColony.Algorithm;
  4. namespace AntColony;
  5. class Program
  6. {
  7. /// <summary></summary>
  8. /// <param name="file">Путь до файла с ребрами</param>
  9. /// <param name="json">Файл представлен в формате JSON вместо TSV</param>
  10. /// <param name="hasHeader">Файл содержит заголовок</param>
  11. /// <param name="iterations">Количество итераций</param>
  12. /// <param name="evaporationRate">Скорость испарения феромонов</param>
  13. public static void Main(FileInfo file, bool json = false, bool hasHeader = false, int iterations = 100, double evaporationRate = 0.1)
  14. {
  15. Console.Write("Чтение файла...");
  16. var sw = new Stopwatch();
  17. sw.Start();
  18. double[][] distances = json ? ParseEdgeJsonAsync(file.FullName).Result! : ParseEdgeFile(file.FullName, hasHeader);
  19. Console.WriteLine($"\rСчитано {distances.Length} вершин за {sw.Elapsed} ({sw.ElapsedMilliseconds} мс).\n");
  20. var aco = new AntColonyOptimizer(distances: distances, evaporationRate: evaporationRate)
  21. .AddAnts<DefaultAnt>(10, 1, 2, 100) // 10 муравьев, для которых расстояние в 2 раза важнее феромонов
  22. .AddAnts<DefaultAnt>(10, 1, 1, 100) // 10 муравьев, для которых расстояние столь же важно, сколько феромоны
  23. .AddAnts<DefaultAnt>(10, 1, 5, 200) // 10 муравьев, для которых расстояние в 5 раз важнее феромонов, и которые оставляют в 2 раза больше феромонов
  24. .CompileAnts(shuffle: true); // перемешиваем муравьев. По надобности можно оставить в исходном порядке
  25. sw.Reset();
  26. Console.CancelKeyPress += (e, f) =>
  27. {
  28. var (tour, distance) = aco.EarlyExit();
  29. Console.WriteLine("\n\n" + new string('-', Console.BufferWidth));
  30. Console.CursorLeft = 0;
  31. Console.WriteLine($"\nРанняя остановка. Время работы: {sw.Elapsed}\n");
  32. if (tour.Count == 0) Console.WriteLine("Путь не найден.");
  33. else Console.WriteLine($"Лучший путь (длина {distance}):\n[ {string.Join(", ", tour)} ]");
  34. };
  35. sw.Start();
  36. var (bestTour, bestDistance) = aco.Solve(iterations);
  37. Console.WriteLine(new string('-', Console.BufferWidth));
  38. Console.WriteLine($"Задача решена за {sw.Elapsed} ({sw.ElapsedMilliseconds} мс).");
  39. if (bestTour.Count == 0)
  40. {
  41. Console.WriteLine("Гамильтонов цикл не найден.");
  42. return;
  43. }
  44. Console.WriteLine($"Лучший путь:\n[ {string.Join(", ", bestTour)} ]");
  45. Console.WriteLine($"Длина: {bestDistance}.");
  46. }
  47. private static async Task<double[][]?> ParseEdgeJsonAsync(string filePath)
  48. {
  49. using var s = File.OpenRead(filePath);
  50. return await JsonSerializer.DeserializeAsync<double[][]>(s);
  51. }
  52. private static double[][] ParseEdgeFile(string filePath, bool skipHeader)
  53. {
  54. List<string> lines = [.. File.ReadAllLines(filePath)];
  55. if (skipHeader) lines.RemoveAt(0);
  56. HashSet<int> vertices = [];
  57. int maxVertex = 0;
  58. foreach (string line in lines)
  59. {
  60. string[] parts = line.Split();
  61. if (parts.Length != 3)
  62. continue;
  63. if (int.TryParse(parts[0], out int v1))
  64. vertices.Add(v1);
  65. if (int.TryParse(parts[1], out int v2))
  66. vertices.Add(v2);
  67. maxVertex = int.Max(maxVertex, v1);
  68. maxVertex = int.Max(maxVertex, v2);
  69. }
  70. double[][] adjacencyMatrix = new double[maxVertex + 1][];
  71. for (int i = 0; i < maxVertex + 1; i++)
  72. {
  73. adjacencyMatrix[i] = new double[maxVertex + 1];
  74. for (int j = 0; j < maxVertex + 1; j++)
  75. {
  76. adjacencyMatrix[i][j] = 0.0;
  77. }
  78. }
  79. foreach (string line in lines)
  80. {
  81. string[] parts = line.Split();
  82. if (parts.Length != 3)
  83. continue;
  84. if (int.TryParse(parts[0], out int v1) &&
  85. int.TryParse(parts[1], out int v2) &&
  86. double.TryParse(parts[2], out double distance))
  87. {
  88. adjacencyMatrix[v1][v2] = distance;
  89. adjacencyMatrix[v2][v1] = distance;
  90. }
  91. }
  92. return adjacencyMatrix;
  93. }
  94. }