Пример #1
0
        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;
                }
            }
        }
Пример #2
0
        /// <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;
        }