예제 #1
0
        private static void Program()
        {
            int n, m;
            var input = Console.ReadLine().Split().Select(c => int.Parse(c)).ToArray();

            n = input[0];
            m = input[1];

            Dsu dsu = new Dsu(n);

            List <Edge> edgeList = new List <Edge>(m);

            for (int i = 0; i < m; i++)
            {
                input = Console.ReadLine().Split().Select(c => int.Parse(c)).ToArray();
                edgeList.Add(new Edge(input[0] - 1, input[1] - 1, input[2]));
            }

            Int64 result = edgeList
                           .OrderBy(e => e.Weight)
                           .Select(e => (Int64)(dsu.Unite(e.From, e.To) ? e.Weight : 0))
                           .Sum();

            Console.WriteLine(result);
        }
예제 #2
0
    public IList <IList <string> > AccountsMerge(IList <IList <string> > accounts)
    {
        var result      = new Dictionary <int, IList <string> >();
        var dsu         = new Dsu(10001);
        var emailToName = new Dictionary <string, string>();
        var emailToId   = new Dictionary <string, int>();
        var id          = 0;

        foreach (var account in accounts)
        {
            var name = account[0];

            for (var i = 1; account.Count > i; ++i)
            {
                var email = account[i];

                if (!emailToName.ContainsKey(email))
                {
                    emailToName.Add(email, name);
                }

                if (!emailToId.ContainsKey(email))
                {
                    emailToId.Add(email, id++);
                }

                dsu.union(emailToId[account[1]], emailToId[email]);
            }
        }

        foreach (var email in emailToName.Keys)
        {
            var idx = dsu.find(emailToId[email]);

            if (result.ContainsKey(idx))
            {
                result[idx].Add(email);
            }
            else
            {
                result.Add(idx, new List <string> {
                    email
                });
            }
        }

        foreach (var idx in result.Keys)
        {
            ((List <string>)result[idx]).Sort(
                (x, y) => string.CompareOrdinal(x, y)
                );
            result[idx].Insert(0, emailToName[result[idx][0]]);
        }

        return(result.Values.ToList());
    }
예제 #3
0
        public void UnionTest()
        {
            var dsu = new Dsu<int>();
            dsu.Add(1);
            dsu.Add(2);

            dsu.Union(1, 2);

            Assert.That(dsu.Find(1), Is.EqualTo(dsu.Find(2)));
        }
예제 #4
0
        public void UnionTest()
        {
            var dsu = new Dsu <int>();

            dsu.Add(1);
            dsu.Add(2);

            dsu.Union(1, 2);

            Assert.That(dsu.Find(1), Is.EqualTo(dsu.Find(2)));
        }
예제 #5
0
    public IList <int> NumIslands2(int rows, int cols, int[][] positions)
    {
        var n      = positions.Length;
        var result = new int[n];
        var grid   = new bool[rows, cols];
        var dsu    = new Dsu(1 + rows * cols);

        for (var i = 0; rows *cols > i; ++i)
        {
            dsu.union(i, rows * cols);
        }

        var connectedComponentsCount = 0;

        for (var i = 0; n > i; ++i)
        {
            var row = positions[i][0];
            var col = positions[i][1];

            if (!grid[row, col])
            {
                var connections = 0;

                grid[row, col] = true;
                dsu.setParent(cols * row + col);

                if (0 < row && grid[row - 1, col])
                {
                    connections += dsu.union(cols * (row - 1) + col, cols * row + col)?1:0;
                }
                if (0 < col && grid[row, col - 1])
                {
                    connections += dsu.union(cols * row - 1 + col, cols * row + col)?1:0;
                }
                if (rows > 1 + row && grid[1 + row, col])
                {
                    connections += dsu.union(cols * (1 + row) + col, cols * row + col)?1:0;
                }
                if (cols > 1 + col && grid[row, 1 + col])
                {
                    connections += dsu.union(cols * row + 1 + col, cols * row + col)?1:0;
                }

                connectedComponentsCount -= (connections - 1);
            }

            result[i] = connectedComponentsCount;
        }

        return(result.ToList());
    }
예제 #6
0
        public long Solve()
        {
            Array.Sort(this.ribs);
            int result = 0;

            Dsu dsu = new Dsu(this.n);

            foreach (Rib rib in this.ribs)
            {
                if (dsu.Merge(rib.From, rib.To))
                {
                    result += rib.Len;
                }
            }

            return(result);
        }
예제 #7
0
        /// <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);
            }
        }
예제 #8
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;
                }
            }
        }
예제 #9
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;
        }