Program.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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="ants">Количество муравьев</param>
  13. /// <param name="alpha">Значение α (определяет вес феромонов)</param>
  14. /// <param name="beta">Значение β (определяет вес расстояния)</param>
  15. /// <param name="evaporationRate">Скорость испарения феромонов</param>
  16. /// <param name="q">Значение Q</param>
  17. public static void Main(FileInfo file, bool json = false, bool hasHeader = false, int iterations = 100, int ants = 20, double alpha = 1, double beta = 2, double evaporationRate = 0.1, double q = 100)
  18. {
  19. Console.Write("Чтение файла...");
  20. var sw = new Stopwatch();
  21. sw.Start();
  22. double[][] distances = json ? ParseEdgeJsonAsync(file.FullName).Result! : ParseEdgeFile(file.FullName, hasHeader);
  23. Console.WriteLine($"\rСчитано {distances.Length} вершин за {sw.Elapsed} ({sw.ElapsedMilliseconds} мс).\n");
  24. var aco = new AntColonyOptimizer(
  25. distances: distances,
  26. evaporationRate: evaporationRate
  27. ).AddAnts<DefaultAnt>(1500).ShuffleAnts();
  28. Console.CancelKeyPress += (e, f) =>
  29. {
  30. var res = aco.EarlyExit();
  31. Console.WriteLine($"\nРанняя остановка.\nЛучший путь: {string.Join(" -> ", res.tour)}\nДлина: {res.distance}");
  32. };
  33. sw.Restart();
  34. var (bestTour, bestDistance) = aco.Solve(iterations);
  35. Console.WriteLine($"Задача решена за {sw.Elapsed} ({sw.ElapsedMilliseconds} мс).");
  36. if (bestTour.Count == 0)
  37. {
  38. Console.WriteLine("Гамильтонов цикл не найден.");
  39. return;
  40. }
  41. Console.WriteLine($"Лучший путь: {string.Join(" -> ", bestTour)}.");
  42. Console.WriteLine($"Итоговое расстояние: {bestDistance}.");
  43. }
  44. private static async Task<double[][]?> ParseEdgeJsonAsync(string filePath)
  45. {
  46. using var s = File.OpenRead(filePath);
  47. return await JsonSerializer.DeserializeAsync<double[][]>(s);
  48. }
  49. private static double[][] ParseEdgeFile(string filePath, bool skipHeader)
  50. {
  51. List<string> lines = [.. File.ReadAllLines(filePath)];
  52. if (skipHeader) lines.RemoveAt(0);
  53. HashSet<int> vertices = [];
  54. int maxVertex = 0;
  55. foreach (string line in lines)
  56. {
  57. string[] parts = line.Split();
  58. if (parts.Length != 3)
  59. continue;
  60. if (int.TryParse(parts[0], out int v1))
  61. vertices.Add(v1);
  62. if (int.TryParse(parts[1], out int v2))
  63. vertices.Add(v2);
  64. maxVertex = int.Max(maxVertex, v1);
  65. maxVertex = int.Max(maxVertex, v2);
  66. }
  67. double[][] adjacencyMatrix = new double[maxVertex + 1][];
  68. for (int i = 0; i < maxVertex + 1; i++)
  69. {
  70. adjacencyMatrix[i] = new double[maxVertex + 1];
  71. for (int j = 0; j < maxVertex + 1; j++)
  72. {
  73. adjacencyMatrix[i][j] = 0.0;
  74. }
  75. }
  76. foreach (string line in lines)
  77. {
  78. string[] parts = line.Split();
  79. if (parts.Length != 3)
  80. continue;
  81. if (int.TryParse(parts[0], out int v1) &&
  82. int.TryParse(parts[1], out int v2) &&
  83. double.TryParse(parts[2], out double distance))
  84. {
  85. adjacencyMatrix[v1][v2] = distance;
  86. adjacencyMatrix[v2][v1] = distance;
  87. }
  88. }
  89. return adjacencyMatrix;
  90. }
  91. }