/// <summary> /// Создание матрицы на основе другой матрицы /// </summary> /// <param name="other">другая матрица</param> public ReductionMatrix(ReductionMatrix other) : base(other) { RealSize = other.RealSize; }
public bool MoveNext() { // если текущий индекс не находиться в конце списка if (index < iterations.Count) { // текущее изображения берется из списка уже // пройденных на итерациях изображений Current = iterations[index++]; return true; } // иначе определение следующего изображения else { // определение действий на текущей итерациии switch (next) { // остановка метода ветвей и границ case IterationState.Stop: { return false; } // начало метода ветвей и границ case IterationState.Start: { // иницилизация данных dsu = new Dsu(Graph.CountVertex()); min = new Branch(float.PositiveInfinity, null); matrix = new ReductionMatrix(Graph.Adjacency); parent = new Branch(matrix.Reduce(), null); tree = new TreeBranch(Graph, parent); // создание и добавление нового изображения ветвления Current = Painter.Drawing(tree); iterations.Add(Current); // перемещение текущего индекса на конец списка index = iterations.Count; // переход в следующее состояние - левое ветвление метода next = IterationState.LeftBranching; return true; } // левое ветвление метода ветвей и границ case IterationState.LeftBranching: { // определение ребер с нулевой стоимостью 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) { TsPath = new Digraph.Path(Graph); // остановка метода ветвей и границ next = IterationState.Stop; return false; } // определение ребра ветвления - ребра с максимальным штрафом edge = zeroEdges.OrderByDescending(e => e.Cost).ToList().First(); // создание левого потомка для данного родителя left = new Branch(parent.LowerBound + edge.Cost, new Digraph.Edge(-edge.Begin, -edge.End, float.PositiveInfinity)); // добавление в дерево ветвлений tree.Add(parent, Branch.Direction.Left, left); // создание и добавление нового изображения ветвления Current = Painter.Drawing(tree); iterations.Add(Current); // перемещение текущего индекса на конец списка index = iterations.Count; // переход в следующее состояние - правое ветвление метода next = IterationState.RightBranching; return true; } // правое ветвление метода case IterationState.RightBranching: { // исключение подмаршрутов для данного ребра ExcludeSubRoute(matrix, dsu, edge); // создание правого потомка для данного родителя right = new Branch(parent.LowerBound + matrix.Reduce(), new Digraph.Edge(edge.Begin, edge.End, Graph[edge.Begin, edge.End])); // добавление в дерево ветвлений tree.Add(parent, Branch.Direction.Right, right); // создание и добавление нового изображения ветвления Current = Painter.Drawing(tree); iterations.Add(Current); // перемещение текущего индекса на конец списка index = iterations.Count; // если размер матрицы достаточно мал if (matrix.RealSize == 2) { // переход в состояние - малый размер матрицы next = IterationState.LittleMatrix; return true; } // выбор новой родительской вершины из еще не подвергшихся ветвлению parent = tree.GetNotGoBranches().OrderBy(b => b.LowerBound).ToList().First(); // проверка на нахождения минимального ветвления и остановки if (min.LowerBound <= parent.LowerBound) { // формирование маршрута коммивояжера TsPath = tree.CreatePathFromBranch(min); // остановка метода next = IterationState.Stop; return false; } // корректировка матрицы для данного ветвления и редуцирование if (parent != right) { // новые непересекающиеся множества вершин dsu = new Dsu(Graph.CountVertex()); // исходная редуцированная матрица matrix = new ReductionMatrix(Graph.Adjacency); // получение текущих вершин для данного ветвления var currentPath = tree.GetEdgesBranching(parent); // исключение всех подмаршрутов foreach (var e in currentPath) ExcludeSubRoute(matrix, dsu, e); // редуцирование матрицы matrix.Reduce(); } // следующая итерация методав ветвей и границ - левое ветвление next = IterationState.LeftBranching; return true; } // малый рамзер матрицы, включение ребер в маршрут case IterationState.LittleMatrix: { // новый родитель parent = right; for (int i = 0; i < matrix.Size && countAdeddEdgeFromMatrix != 1; i++) for (int j = 0; j < matrix.Size && countAdeddEdgeFromMatrix != 1; j++) { if (matrix[i, j] == 0) { // исключение данного ребра из матрицы matrix[i, j] = float.PositiveInfinity; // создание и добавление правого ветвления к родителю right = new Branch(parent.LowerBound, new Digraph.Edge(i, j, Graph[i, j])); tree.Add(parent, Branch.Direction.Right, right); // новый родитель parent = right; // продолжать включать ребра в маршрут на следующей итерации countAdeddEdgeFromMatrix++; } } // если следующая итерация та же if (countAdeddEdgeFromMatrix == 1) { // создание и добавление нового изображения ветвления Current = Painter.Drawing(tree); iterations.Add(Current); // перемещение текущего индекса на конец списка index = iterations.Count; // на следующей итерации будет включено второе ребро countAdeddEdgeFromMatrix++; return true; } else // все ребра включены для данной матрицы countAdeddEdgeFromMatrix = 0; // иначе проверка на новое минимальное ветвление if (parent.LowerBound < min.LowerBound) min = parent; // создание и добавление нового изображения ветвления Current = Painter.Drawing(tree); iterations.Add(Current); // перемещение текущего индекса на конец списка index = iterations.Count; // выбор новой родительской вершины из еще не подвергшихся ветвлению parent = tree.GetNotGoBranches().OrderBy(b => b.LowerBound).ToList().First(); // проверка на нахождения минимального ветвления и остановки if (min.LowerBound <= parent.LowerBound) { // формирование маршрута коммивояжера TsPath = tree.CreatePathFromBranch(min); // остановка метода next = IterationState.Stop; return false; } // корректировка матрицы для данного ветвления и редуцирование if (parent != right) { // новые непересекающиеся множества вершин dsu = new Dsu(Graph.CountVertex()); // исходная редуцированная матрица matrix = new ReductionMatrix(Graph.Adjacency); // получение текущих вершин для данного ветвления var currentPath = tree.GetEdgesBranching(parent); // исключение всех подмаршрутов foreach (var e in currentPath) ExcludeSubRoute(matrix, dsu, e); // редуцирование матрицы matrix.Reduce(); } // следующая итерация методав ветвей и границ - левое ветвление next = IterationState.LeftBranching; return true; } default: return false; } } }
/// <summary> /// Исключение подмаршрутов в графе /// </summary> /// <param name="matrix">редуцированная матрица</param> /// <param name="dsu">непересекающиеся множества вершин</param> /// <param name="edges">ребро ветвления, которое уже находяться в маршруте или не входит в него</param> private static void ExcludeSubRoute(ReductionMatrix matrix, Dsu dsu, Digraph.Edge edge) { // если ребро не входит в ветвление if (edge.Begin < 0 || edge.End < 0) // исключение данного ребра из матрицы matrix[Math.Abs(edge.Begin), Math.Abs(edge.End)] = float.PositiveInfinity; // ребро входит в ветвление else { // исключение строки и столбца из матрицы, соответсвующие началу и концу ребра matrix.DeleteRowColumn(edge.Begin, edge.End); // исключение оставщихся подмаршрутов for (int i = 0; i < matrix.Size; i++) for (int j = 0; j < matrix.Size; j++) if (dsu.Find(edge.Begin) == dsu.Find(i) && dsu.Find(edge.End) == dsu.Find(j)) matrix[j, i] = float.PositiveInfinity; // объединение двух вершин графа в одно множество dsu.Union(edge.Begin, edge.End); } }
/// <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; }