/// <summary> /// Отрисовка ориентированного графа с выделенным маршрутом /// </summary> /// <param name="graph">орг. граф</param> /// <param name="path">маршрут</param> /// <returns>битовое изображение</returns> public static Bitmap Drawing(Digraph graph, Digraph.Path path) { if (graph == null || graph.CountVertex() == 0) throw new Exception("Невозможно отрисовать граф. Граф пуст."); if (path == null || !path.IsExists()) return Drawing(graph); string script = "digraph G { nrankdir=LR node [style=\"filled\", fillcolor=\"skyblue\"]"; for (int i = 0; i < graph.CountVertex(); i++) script += (i + 1) + " "; for (int i = 0; i < graph.CountVertex(); i++) for (int j = 0; j < graph.CountVertex(); j++) if (!float.IsInfinity(graph[i, j])) { script += (i + 1) + " -> " + (j + 1) + " [label=\"" + graph[i, j] + "\""; if (path.IsContain(new Digraph.Edge(i, j, graph[i, j]))) script += ", fontcolor=\"firebrick\", color=\"firebrick2\", penwidth=3, weight=1"; script += "] "; } script += "}"; return RenderingOnGraphviz(script); }
/// <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="graph">орг. граф</param> /// <returns>битовое изображение</returns> public static Bitmap Drawing(Digraph graph) { if (graph == null || graph.CountVertex() == 0) throw new Exception("Невозможно отрисовать граф. Граф не задан."); string script = "digraph G { nrankdir=LR node [style=\"filled\", fillcolor=\"skyblue\"]"; for (int i = 0; i < graph.CountVertex(); i++) script += (i + 1) + " "; for (int i = 0; i < graph.CountVertex(); i++) for (int j = 0; j < graph.CountVertex(); j++) if (!float.IsInfinity(graph[i, j])) script += (i + 1) + " -> " + (j + 1) + " [label=\"" + graph[i, j] + "\"] "; script += "}"; return RenderingOnGraphviz(script); }
/// <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; }