/// <summary> /// Создание пошагового метода ветвей и границ /// </summary> /// <param name="graph">орг. граф</param> public BranchAndBound(Digraph graph) { // метод ветвей и границ для указанного графа Graph = graph; // переход в следующее состояние next = IterationState.Start; // создание пустого маршрута коммивояжера TsPath = new Digraph.Path(Graph); if (Graph.CountVertex() == 0) { // пустой маршрут // окончание метода next = IterationState.Stop; } else if (Graph.CountVertex() == 1) { // маршрут из одной вершины TsPath.Append(new Digraph.Edge(0, 0, 0)); // окончание метода next = IterationState.Stop; } else if (Graph.CountVertex() == 2) { // маршрут из двух вершин TsPath.Append(new Digraph.Edge(0, 1, Graph[0, 1])); TsPath.Append(new Digraph.Edge(1, 0, Graph[1, 0])); // окончание метода next = IterationState.Stop; } }
/// <summary> /// Создание маршрута на основе ветвления /// </summary> /// <param name="branch">ветвление</param> /// <returns>маршрут</returns> public Digraph.Path CreatePathFromBranch(Branch branch) { var edges = GetEdgesBranching(branch); var path = new Digraph.Path(Graph); foreach (var e in edges) if (e.Begin >= 0 && e.End >= 0) path.Append(e); return path; }
/// <summary> /// Нахождение маршрута коммивояжера /// </summary> /// <param name="graph">ограф. граф</param> /// <returns>маршрут коммивояжера</returns> public static Digraph.Path Tsp(Digraph graph) { // маршрут коммивояжера var TsPath = new Digraph.Path(graph); // если граф пуст if (graph.CountVertex() == 0) { // пустой маршрут return TsPath; } // если граф имеет одну вершину else if (graph.CountVertex() == 1) { TsPath.Append(new Digraph.Edge(0, 0, 0)); // маршрут для одной вершины return TsPath; } // если граф имеет две вершины else if (graph.CountVertex() == 2) { TsPath.Append(new Digraph.Edge(0, 1, graph[0, 1])); TsPath.Append(new Digraph.Edge(1, 0, graph[1, 0])); // маршрут для двух вершин return TsPath; } /// Создания неперекающихся множеств вершин в графе, /// для определения и исключения подмаршрутов графа var dsu = new Dsu(graph.CountVertex()); // минимальное ветвление var minBranch = new Branch(float.PositiveInfinity, null); /// Получение исходной матрицы смежности данного графа var matrix = new ReductionMatrix(graph.Adjacency); /// Создание корня и дерева ветвления var parentBranch = new Branch(matrix.Reduce(), null); var tree = new TreeBranch(graph, parentBranch); for (; ; ) { // ребра с нулевой стоимостью var zeroEdges = new List<Digraph.Edge>(); // Получение всех ребер и соответсвующих штрафов for (int i = 0; i < matrix.Size; i++) for (int j = 0; j < matrix.Size; j++) if (matrix[i, j] == 0) zeroEdges.Add(new Digraph.Edge(i, j, matrix.MinInRow(i, j) + matrix.MinInColumn(j, i))); // если нет ребер ветвления - нет маршрута коммивояжера if (zeroEdges.Count == 0) return new Digraph.Path(graph); /// Определение ребра ветвления - ребра с максимальным штрафом var branchingEdge = zeroEdges.OrderByDescending(e => e.Cost).ToList().First(); /// Процесс ветления - не включая данное ребро var leftBranch = new Branch(parentBranch.LowerBound + branchingEdge.Cost, new Digraph.Edge(-branchingEdge.Begin, -branchingEdge.End, float.PositiveInfinity)); // добавление ветвления в дерево tree.Add(parentBranch, Branch.Direction.Left, leftBranch); /// Процесс ветления - включая данное ребро ExcludeSubRoute(matrix, dsu, branchingEdge); var rightBranch = new Branch(parentBranch.LowerBound + matrix.Reduce(), new Digraph.Edge(branchingEdge.Begin, branchingEdge.End, graph[branchingEdge.Begin, branchingEdge.End])); // добавление ветвления в дерево tree.Add(parentBranch, Branch.Direction.Right, rightBranch); /// Проверка на достаточность размера матрцицы if (matrix.RealSize == 2) { // новый родитель parentBranch = rightBranch; /// Добавление оставщихся ребер в дерево ветвлений for (int i = 0; i < matrix.Size; i++) for (int j = 0; j < matrix.Size; j++) if (matrix[i, j] == 0) { // новый потомок rightBranch = new Branch(parentBranch.LowerBound, new Digraph.Edge(i, j, graph[i, j])); tree.Add(parentBranch, Branch.Direction.Right, rightBranch); // потомок теперь родитель parentBranch = rightBranch; } /// Определение нового минимального ветвления if (parentBranch.LowerBound < minBranch.LowerBound) minBranch = parentBranch; } /// Выбор новой родительской вершины из еще не подвергшихся ветвлению parentBranch = tree.GetNotGoBranches().OrderBy(b => b.LowerBound).ToList().First(); /// Проверка на нахождения минимального ветвления и остановки if (minBranch.LowerBound <= parentBranch.LowerBound) break; /// Корректировка матрицы для данного ветвления и редуцирование if (parentBranch != rightBranch) { // новые непересекающиеся множества вершин dsu = new Dsu(graph.CountVertex()); // исходная редуцированная матрица matrix = new ReductionMatrix(graph.Adjacency); // получение текущих вершин для данного ветвления var currentPath = tree.GetEdgesBranching(parentBranch); // исключение всех подмаршрутов foreach (var e in currentPath) ExcludeSubRoute(matrix, dsu, e); // редуцирование матрицы matrix.Reduce(); } } // формирование маршрута коммивояжера TsPath = tree.CreatePathFromBranch(minBranch); return TsPath; }