using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MathModTasks
{
///
/// Класс для решения задачи комивояжера
///
class Сommivoyageur
{
string readPath;
string savingPath;
int[,] time; //Массив, содержащий введённые значения
int[] f = new int[0]; //Массив, содержащий длины путей
int uzli; //Длина строк и столбцов массива time
string[] puti = new string[0]; // Массив, содержащий полученные пути
///
/// Метод, записывающий путь файла, из которого берутся данные и в который записываются результаты
///
/// Путь файла, из которого берутся данные
/// Путь файла, в который записываются результаты
public Сommivoyageur(string readPath, string savingPath)
{
this.readPath = readPath;
this.savingPath = savingPath;
}
///
/// Метод для поиска совпадений среди строки
///
/// Номер рассматриваемого пути
/// Номер столбца в рассматриваемой строке
/// Возвращает True, если совпадений нет и False, если есть
bool PoiskSovpad(int pi, int j)
{
bool sch = true; //совпадений нет
foreach (string s in puti[pi].Split('-'))
{
if (Convert.ToInt32(s) == j)
{
sch = false; //есть
break;
}
}
return sch;
}
///
/// Метод, в котором вызывается поиск и подсчёт длин путей
///
void CalculatePaths()
{
for (int i = 0; i < uzli; i++) //точка отправления - передаем в метод для поиска путей
{
Array.Resize(ref puti, puti.Length + 1); //Увеличение размера массива путей
Array.Resize(ref f, f.Length + 1); //Увеличение размера массива длины путей
puti[puti.Length - 1] = $"{i + 1}"; //Запись в начало пути стартового элемента
puti = Schet(puti.Length - 1, i); // Добавление нового пути
}
}
///
/// Основной вычислительный метод, в котором ведётся подсчёт длин путей и добавление их пунктов и длин в массивы
///
/// Номер рассматриваемого пути
/// Номер рассматриваемой строки
/// Возвращает изменённый массив путей
string[] Schet(int pi, int i1)
{
int min = time[i1, 0], mi2 = 0;
if (puti[pi].Length != time.GetLength(0) * 2 - 1) //Проверка, что количество узлов в пути ниже количества узлов в массиве (длина строк и столбцов массива умножается на 2, потому что в пятх также считаются '-' между узлами)
{
for (int j = 0; j < time.GetLength(0); j++) //Просмотр строки в поиске элемента, который не был записан в пути
{
if (time[i1, j] != 0)
{
if (PoiskSovpad(pi, j + 1))
{
min = time[i1, j]; //Первый элемент строки, не встречавшийся до этого в пути, берётся за минимум
mi2 = j; //Запись индекса элемента
break;
}
}
}
for (int j = 0; j < time.GetLength(0); j++) //Просмотр строки в поисках элемента строки который меньше ранее записанного первого элемента, не встречающегося в пути
{
if (time[i1, j] != 0)
{
if (PoiskSovpad(pi, j + 1))
{
if (min > time[i1, j] || (min == time[i1, j] && j == mi2)) //Если элемент меньше минимума или равен ему и не является им же, то он является новым минимумом и его индекс записывается
{
min = time[i1, j];
mi2 = j;
}
}
}
}
for (int j = 0; j < time.GetLength(0); j++) //Добавление узлов в путь и расстояния между ними
{
if (PoiskSovpad(pi, j + 1))
if (min == time[i1, j] && j != mi2) //Если нашёл элемент, равный минимуму, но не являющийся им
{
string s = puti[pi]; //Запись во временную переменную расматриваемого пути
int ff = f[pi]; //Запись во временную переменную длину расматриваемого пути
puti[pi] += $"-{mi2 + 1}"; //Добавление в путь узла, в котором находится минимум строки
f[pi] += min; //Добавление к длине пути минимум строки
puti = Schet(pi, mi2); //Рассчёт дальнейшего пути, начиная с узла, в котором находится минимум
mi2 = j; //Запись индекса ещё одного минимума, встречающегося в строке
Array.Resize(ref puti, puti.Length + 1); //Увеличение размера массива путей
Array.Resize(ref f, f.Length + 1);//Увеличение размера массива длины путей
pi = f.Length - 1;//Индексу присваивается значение последнего индекса длины путей
puti[pi] = s;//В путь, по последнему индексу массива длины путей записывается временная строка
f[pi] = ff;//В массив длин путей, по последнему индексу массива длины путей записывается временная переменная с длиной
}
}
}
else //Когда доходит до последнего узла он берет первый узел в пути и добавляет его в конец
{
foreach (string s in puti[pi].Split('-'))
{
mi2 = Convert.ToInt32(s);
min = time[i1, mi2 - 1];
break;
}
puti[pi] += $"-{mi2}";
f[pi] += min;
return puti;
}
puti[pi] += $"-{mi2 + 1}";
f[pi] += min;
puti = Schet(pi, mi2);
return puti;
}
///
/// Основной метод, в котором читаются данные из файла, вызывается вычисляющий метод, и результаты записываются в файл
///
public void Calculate()
{
ReadSaveData.ReadData(readPath, ref time);
uzli = time.GetLength(0);
CalculatePaths();
ReadSaveData.WriteToFile(savingPath, uzli, puti, f);
}
}
}