Сommivoyageur.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace MathModTasks
  8. {
  9. /// <summary>
  10. /// Класс для решения задачи комивояжера
  11. /// </summary>
  12. class Сommivoyageur
  13. {
  14. string readPath;
  15. string savingPath;
  16. int[,] time; //Массив, содержащий введённые значения
  17. int[] f = new int[0]; //Массив, содержащий длины путей
  18. int uzli; //Длина строк и столбцов массива time
  19. string[] puti = new string[0]; // Массив, содержащий полученные пути
  20. /// <summary>
  21. /// Метод, записывающий путь файла, из которого берутся данные и в который записываются результаты
  22. /// </summary>
  23. /// <param name="readPath">Путь файла, из которого берутся данные</param>
  24. /// <param name="savingPath">Путь файла, в который записываются результаты</param>
  25. public Сommivoyageur(string readPath, string savingPath)
  26. {
  27. this.readPath = readPath;
  28. this.savingPath = savingPath;
  29. }
  30. /// <summary>
  31. /// Метод для поиска совпадений среди строки
  32. /// </summary>
  33. /// <param name="pi">Номер рассматриваемого пути</param>
  34. /// <param name="j">Номер столбца в рассматриваемой строке</param>
  35. /// <returns>Возвращает True, если совпадений нет и False, если есть</returns>
  36. bool PoiskSovpad(int pi, int j)
  37. {
  38. bool sch = true; //совпадений нет
  39. foreach (string s in puti[pi].Split('-'))
  40. {
  41. if (Convert.ToInt32(s) == j)
  42. {
  43. sch = false; //есть
  44. break;
  45. }
  46. }
  47. return sch;
  48. }
  49. /// <summary>
  50. /// Метод, в котором вызывается поиск и подсчёт длин путей
  51. /// </summary>
  52. void CalculatePaths()
  53. {
  54. for (int i = 0; i < uzli; i++) //точка отправления - передаем в метод для поиска путей
  55. {
  56. Array.Resize(ref puti, puti.Length + 1); //Увеличение размера массива путей
  57. Array.Resize(ref f, f.Length + 1); //Увеличение размера массива длины путей
  58. puti[puti.Length - 1] = $"{i + 1}"; //Запись в начало пути стартового элемента
  59. puti = Schet(puti.Length - 1, i); // Добавление нового пути
  60. }
  61. }
  62. /// <summary>
  63. /// Основной вычислительный метод, в котором ведётся подсчёт длин путей и добавление их пунктов и длин в массивы
  64. /// </summary>
  65. /// <param name="pi">Номер рассматриваемого пути</param>
  66. /// <param name="i1">Номер рассматриваемой строки</param>
  67. /// <returns>Возвращает изменённый массив путей</returns>
  68. string[] Schet(int pi, int i1)
  69. {
  70. int min = time[i1, 0], mi2 = 0;
  71. if (puti[pi].Length != time.GetLength(0) * 2 - 1) //Проверка, что количество узлов в пути ниже количества узлов в массиве (длина строк и столбцов массива умножается на 2, потому что в пятх также считаются '-' между узлами)
  72. {
  73. for (int j = 0; j < time.GetLength(0); j++) //Просмотр строки в поиске элемента, который не был записан в пути
  74. {
  75. if (time[i1, j] != 0)
  76. {
  77. if (PoiskSovpad(pi, j + 1))
  78. {
  79. min = time[i1, j]; //Первый элемент строки, не встречавшийся до этого в пути, берётся за минимум
  80. mi2 = j; //Запись индекса элемента
  81. break;
  82. }
  83. }
  84. }
  85. for (int j = 0; j < time.GetLength(0); j++) //Просмотр строки в поисках элемента строки который меньше ранее записанного первого элемента, не встречающегося в пути
  86. {
  87. if (time[i1, j] != 0)
  88. {
  89. if (PoiskSovpad(pi, j + 1))
  90. {
  91. if (min > time[i1, j] || (min == time[i1, j] && j == mi2)) //Если элемент меньше минимума или равен ему и не является им же, то он является новым минимумом и его индекс записывается
  92. {
  93. min = time[i1, j];
  94. mi2 = j;
  95. }
  96. }
  97. }
  98. }
  99. for (int j = 0; j < time.GetLength(0); j++) //Добавление узлов в путь и расстояния между ними
  100. {
  101. if (PoiskSovpad(pi, j + 1))
  102. if (min == time[i1, j] && j != mi2) //Если нашёл элемент, равный минимуму, но не являющийся им
  103. {
  104. string s = puti[pi]; //Запись во временную переменную расматриваемого пути
  105. int ff = f[pi]; //Запись во временную переменную длину расматриваемого пути
  106. puti[pi] += $"-{mi2 + 1}"; //Добавление в путь узла, в котором находится минимум строки
  107. f[pi] += min; //Добавление к длине пути минимум строки
  108. puti = Schet(pi, mi2); //Рассчёт дальнейшего пути, начиная с узла, в котором находится минимум
  109. mi2 = j; //Запись индекса ещё одного минимума, встречающегося в строке
  110. Array.Resize(ref puti, puti.Length + 1); //Увеличение размера массива путей
  111. Array.Resize(ref f, f.Length + 1);//Увеличение размера массива длины путей
  112. pi = f.Length - 1;//Индексу присваивается значение последнего индекса длины путей
  113. puti[pi] = s;//В путь, по последнему индексу массива длины путей записывается временная строка
  114. f[pi] = ff;//В массив длин путей, по последнему индексу массива длины путей записывается временная переменная с длиной
  115. }
  116. }
  117. }
  118. else //Когда доходит до последнего узла он берет первый узел в пути и добавляет его в конец
  119. {
  120. foreach (string s in puti[pi].Split('-'))
  121. {
  122. mi2 = Convert.ToInt32(s);
  123. min = time[i1, mi2 - 1];
  124. break;
  125. }
  126. puti[pi] += $"-{mi2}";
  127. f[pi] += min;
  128. return puti;
  129. }
  130. puti[pi] += $"-{mi2 + 1}";
  131. f[pi] += min;
  132. puti = Schet(pi, mi2);
  133. return puti;
  134. }
  135. /// <summary>
  136. /// Основной метод, в котором читаются данные из файла, вызывается вычисляющий метод, и результаты записываются в файл
  137. /// </summary>
  138. public void Calculate()
  139. {
  140. ReadSaveData.ReadData(readPath, ref time);
  141. uzli = time.GetLength(0);
  142. CalculatePaths();
  143. ReadSaveData.WriteToFile(savingPath, uzli, puti, f);
  144. }
  145. }
  146. }