private void Calculate() { BnBNodeData nData = new BnBNodeData(Cities); // заносим начальные данные из коллекции городов tmrTimer.Start(); //запуск таймера _liInfo = new List <string>(); nData.ReductedMatrix(); // приводим матрице по столбцам и строкам nData.PowCalc(); // подсчет степеней у нулевых элементов nData.LogMatrix(); // вывод в логи для отладки _greatParentNode = new BnBNode(null, nData); // создаем первый родительский узел с данными // Обход GoDown(_greatParentNode, null); liPath = FindBest(_greatParentNode, new List <string>()); // получаем лучшие пути // Записываем лучшие пути в отладочные данные _liInfo.Add("------результат------"); foreach (string lp in liPath) { _liInfo.Add(lp); } tmrTimer.Stop(); //остановка таймера // Вычисление завершено OnFinally(new EventArgs()); //CitiesCollection pathCities = BestPath; //List<CitiesCollection> pathCitiesList = BestPathList; }
/// <summary> /// Находит лучшие пути /// </summary> /// <param name="currentNode">Текущий узед</param> /// <param name="liPath">Накопленный путь ввиде списка</param> /// <returns></returns> private List <string> FindBest(BnBNode currentNode, List <string> liPath) { if (currentNode.Data.Length == 2) { if (currentNode.Data.SummWeight <= _dCriterialWeight) { liPath.Add(currentNode.Index + " | " + currentNode.Data.Path.PiePath[0] + " | " + currentNode.Data.SummWeight); } return(liPath); } for (int i = 0; i < currentNode.Nodes.Count; i++) { if (currentNode.Nodes[i].Forbidden == false) { FindBest(currentNode.Nodes[i], liPath); } } return(liPath); }
/// <summary> /// Обход вверх /// </summary> private void GoUp(BnBNode currentNode, BnBNode calledNode) { while (currentNode != calledNode) { //получили родителя BnBNode parentNode = currentNode.ParentNode; if (parentNode == null) { return; } BnBNode childNode = currentNode; for (int i = 0; i < parentNode.Nodes.Count; i++) { if (parentNode.Nodes[i] != childNode) { if (parentNode.Nodes[i].Data.SummWeight <= _dCriterialWeight) { if (parentNode.Nodes[i].Viewed == false) { // Обход вниз для i-го ребенка _stCountDown++; currentNode.Viewed = true; GoDown(parentNode.Nodes[i], currentNode); return; } } else { parentNode.Nodes[i].Forbidden = true; } } } currentNode.Viewed = true; // Продолжаем функцию ОбходВверх для родителя родителя. (поднимаемся на уровень выше) currentNode = currentNode.ParentNode; } return; }
/// <summary> /// Обход вниз /// </summary> /// <param name="parent">Текущий родительский узел</param> /// <param name="calledNode">Вызвавший узел</param> private void GoDown(BnBNode currentNode, BnBNode calledNode) { bool _continue = true; while (_continue) { // Если текущий суммарный вес больше, чем Критериальный суммарный вес if (currentNode.Data.SummWeight > _dCriterialWeight) { currentNode.Forbidden = true; currentNode.Viewed = true; // Запускаем функцию ОбходВверх(текущий_узел); GoUp(currentNode, calledNode); _continue = false; break; } // Если матрица 2х2 if (currentNode.Data.Length == 2) { for (int i = 0; i < currentNode.Data.Length; i++) { for (int j = 0; j < currentNode.Data.Length; j++) { if (currentNode.Data.Distance[i, j].Value == 0) { int childI = currentNode.Data.VerIndexes[i]; int childJ = currentNode.Data.HorIndexes[j]; currentNode.Data.RecalcPath(childI, childJ); } } } _dCriterialWeight = currentNode.Data.SummWeight; //currentNode.Data.LogMatrix(); currentNode.Viewed = true; _strCountUp++; // Запускаем функцию ОбходВверх(текущий_узел); GoUp(currentNode, calledNode); _continue = false; break; } //currentNode.Data.LogMatrix(); if (currentNode.Viewed == false) { double dMaxPowValue = currentNode.Data.GetMaxPowValue(); for (int i = 0; i < currentNode.Data.Length; i++) { for (int j = 0; j < currentNode.Data.Length; j++) { if (currentNode.Data.Distance[i, j].Pow == dMaxPowValue) { // Пересечение с максимальным значением степени int childI = currentNode.Data.VerIndexes[i]; int childJ = currentNode.Data.HorIndexes[j]; // Берется дуга i,j BnBNodeData childDataFirst = new BnBNodeData(currentNode.Data, i, j); BnBNode childNodeFirst = new BnBNode(currentNode, childDataFirst); childDataFirst.RecalcPath(childI, childJ); // добавляем дугу в маршрут и исключаем закольцованность childDataFirst.ReductedMatrix(); // приведение матрицы childDataFirst.PowCalc(); // подсчет степеней матрицы //childDataFirst.LogMatrix(); // Не берется дуга i,j BnBNodeData childDataSecond = new BnBNodeData(currentNode.Data); BnBNode childNodeSecond = new BnBNode(currentNode, childDataSecond); childDataSecond.RemoveLoopback(childI, childJ); childDataSecond.RemoveLoopback(childJ, childI); childDataSecond.ReductedMatrix(); childDataSecond.PowCalc(); //childDataSecond.LogMatrix(); currentNode.Nodes.Add(childNodeFirst); currentNode.Nodes.Add(childNodeSecond); // служебные данные _lNodeCount += 2; // количество узлов в дереве _liInfo.Add(" "); _liInfo.Add(String.Format("№: {0:00000}\tParent:{1:00000}", childNodeFirst.Index, childNodeFirst.ParentNode.Index)); _liInfo.Add(String.Format("Размерность: {0:#}x{1:#}", childNodeFirst.Data.Length, childNodeFirst.Data.Length)); _liInfo.Add(String.Format("Длина пути: {0:000.00}", childNodeFirst.Data.SummWeight)); //_liInfo.AddRange( childNodeFirst.Data.ListInfo() ); _liInfo.Add(" "); _liInfo.Add(String.Format("№: {0:00000}\tParent:{1:00000}", childNodeSecond.Index, childNodeSecond.ParentNode.Index)); _liInfo.Add(String.Format("Размерность: {0:#}x{1:#}", childNodeSecond.Data.Length, childNodeSecond.Data.Length)); _liInfo.Add(String.Format("Длина пути: {0:000.00}", childNodeSecond.Data.SummWeight)); //_liInfo.AddRange( childNodeSecond.Data.ListInfo() ); break; } } } // Находим минимальный суммарный вес у потомков double minSummWeight = double.MaxValue; for (int i = 0; i < currentNode.Nodes.Count; i++) { if (currentNode.Nodes[i].Data.SummWeight < minSummWeight) { minSummWeight = currentNode.Nodes[i].Data.SummWeight; } } // Запускаем функцию ОбходВниз для первого дочернего элемента с минимальным суммарным весом for (int i = 0; i < currentNode.Nodes.Count; i++) { if (currentNode.Nodes[i].Data.SummWeight == minSummWeight) { _stCountDown++; //GoDown(currentNode.Nodes[i]); currentNode = currentNode.Nodes[i]; continue; } } } } return; }