DefaultAnt.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. namespace AntColony.Algorithm;
  2. /// <summary>
  3. /// Стандартная реализация муравья
  4. /// </summary>
  5. /// <param name="alpha">Значение α (определяет вес феромонов)</param>
  6. /// <param name="beta">Значение β (определяет вес расстояния)</param>
  7. /// <param name="Q">Значение Q (множитель депозита феромонов)</param>
  8. public class DefaultAnt(double alpha = 1, double beta = 1, double Q = 100) : IAnt
  9. {
  10. private List<int> tour = [];
  11. private double distance = double.PositiveInfinity;
  12. /// <inheritdoc/>
  13. public (List<int> tour, double distance)? ConstructTour(ref double[][] distances, ref double[][] pheromones)
  14. {
  15. tour = [];
  16. distance = double.PositiveInfinity;
  17. var visited = new bool[distances.Length];
  18. var curCity = Random.Shared.Next(distances.Length);
  19. tour.Add(curCity);
  20. visited[curCity] = true;
  21. // Пока остались непосещенные города
  22. while (tour.Count < distances.Length)
  23. {
  24. var sel = SelectNextCity(curCity, ref visited, ref distances, ref pheromones);
  25. while (!sel.HasValue) sel = SelectNextCity(curCity, ref visited, ref distances, ref pheromones);
  26. // Если не можем найти следующий город - самоубиваемся
  27. if (sel is not { } nextCity) return null;
  28. tour.Add(nextCity);
  29. visited[nextCity] = true;
  30. curCity = nextCity;
  31. }
  32. // Если не можем найти путь до стартовой точки - самоубиваемся
  33. if (distances[curCity][tour[0]] == 0) return null;
  34. tour.Add(tour[0]);
  35. distance = CalculateTourDistance(tour, ref distances);
  36. return (tour, distance);
  37. }
  38. /// <inheritdoc/>
  39. public void UpdatePheromones(ref double[][] pheromones)
  40. {
  41. double deposit = Q / distance;
  42. for (int i = 0; i < tour.Count - 1; i++)
  43. {
  44. int cityA = tour[i];
  45. int cityB = tour[i + 1];
  46. pheromones[cityA][cityB] += deposit;
  47. pheromones[cityB][cityA] += deposit; // Ненаправленный граф
  48. }
  49. }
  50. private static double CalculateTourDistance(List<int> tour, ref double[][] distances)
  51. {
  52. double distance = 0;
  53. for (int i = 0; i < tour.Count - 1; i++)
  54. {
  55. distance += distances[tour[i]][tour[i + 1]];
  56. }
  57. return distance;
  58. }
  59. private int? SelectNextCity(int currentCity, ref bool[] visited, ref double[][] distances, ref double[][] pheromones)
  60. {
  61. var probabilities = new double[distances.Length];
  62. double probabilitiesSum = 0;
  63. // Вероятности для каждого непосещенного города
  64. for (int i = 0; i < distances.Length; i++)
  65. {
  66. if (!visited[i])
  67. {
  68. if (distances[currentCity][i] == 0) continue;
  69. probabilities[i] = Math.Pow(pheromones[currentCity][i], alpha) *
  70. Math.Pow(1.0 / distances[currentCity][i], beta);
  71. probabilitiesSum += probabilities[i];
  72. }
  73. }
  74. // Случайно выбираем следующий город (по вероятностям)
  75. double randomValue = Random.Shared.NextDouble() * probabilitiesSum;
  76. //double sum = 0;
  77. for (int i = 0; i < distances.Length; i++)
  78. {
  79. if (!visited[i])
  80. {
  81. //sum += probabilities[i];
  82. if (probabilities[i] >= randomValue)
  83. {
  84. return i;
  85. }
  86. }
  87. }
  88. return null;
  89. }
  90. }