/// <summary>
        ///  Находит все минимальные гамаки в графе
        /// </summary>
        /// <returns>Возвращает множество гамаков для каждой вершины</returns>
        /// <param name="gi">Граф</param>
        public static List<SortedSet<int>> GetAllHammocks(GraphInfo gi)
        {
            var gp = gi.Gr;
            var tgp = TransposeGraph(gp);
            var dp1 = CalcDynamicOnGraph(gp, gi.EndVertex);
            var dp2 = CalcDynamicOnGraph(tgp, gi.StartVertex);

            // Оставляем только нужные вершины (переходы)
            if (gi.Include != null)
            {
                for (int i = 0; i < gp.Count; i++)
                {
                    if (!gi.Include.Contains(i))
                    {
                        dp1[i].Clear();
                        dp2[i].Clear();
                    }
                }
            }

            // Удаляем гамаки между позициями (оставляем между переходами)
            for (int i = 0; i < gp.Count; i++)
            {
                dp1[i].Remove(i);

                var newSet = new SortedSet<int>();

                foreach (int v in dp1[i])
                    if (dp2[v].Contains(i))
                        newSet.Add(v);

                dp1[i] = newSet;
            }

            // Оставляем минимальные гамаки
            // Гамак является минимальным, если его нельзя разбить на два гамака
            for (int v = 0; v < dp1.Count; v++)
                dp1[v].RemoveWhere(x => IsBadHammock(dp1, v, x));

            return dp1;
        }
        /// <summary>
        ///  Находит гамак, начинающийся в данной вершине максимального размера меньше заданного.
        ///  Это есть ребенок данного гамака
        /// </summary>
        /// <returns>Гамак</returns>
        /// <param name="gi">Граф</param>
        /// <param name="v">Номер вершины</param>
        /// <param name="size">Размер текущего гамака</param>
        protected virtual HammockTree GetChildren(GraphInfo gi, int v, int size)
        {
            var ans = new HammockTree();

            foreach (var node in gi.HammocksStartedAtVertex[v])
                if (gi.ListOfHammocks[node].Size > ans.Size &&
                    gi.ListOfHammocks[node].Size < size)
                    ans = gi.ListOfHammocks[node];

            return ans;
        }
        /// <summary>
        ///  Строит дерево гамаков по данному графу
        /// </summary>
        /// <returns>Возвращает указатель на корень дерева</returns>
        /// <param name="gi">Граф</param>
        public static HammockTree CreateHammockTree(GraphInfo gi)
        {
            var root = new HammockTree();

            foreach (var node in gi.ListOfHammocks)
                if (node.Size > root.Size)
                    root = node;

            root.FindChildren(gi);

            return root;
        }
        /// <summary>
        ///  Ищем всех потомков данной вершины в дереве гамаков
        ///  (то есть все гамаки, которые содержит этот гамак)
        /// </summary>
        /// <param name="gi">Граф</param>
        protected virtual void FindChildren(GraphInfo gi)
        {
            var used = new SortedSet<int>();
            var q = new Queue<int>();

            q.Enqueue(Start);
            used.Add(Start);

            while (q.Count > 0)
            {
                int cur = q.Dequeue();

                if (cur == End)
                    continue;

                if (gi.HammocksStartedAtVertex[cur].Count > 0)
                {
                    var next = GetChildren(gi, cur, Size);

                    if (next.Size > 0)
                    {
                        if (!used.Contains(next.End))
                        {
                            used.Add(next.End);
                            q.Enqueue(next.End);
                        }

                        Childs.Add(next);
                        next.Parent = this;
                        next.FindChildren(gi);

                        continue;
                    }
                }

                foreach (int next in gi.Gr[cur])
                {
                    if (!used.Contains(next))
                    {
                        used.Add(next);
                        q.Enqueue(next);
                    }
                }

            }

            foreach (var child in Childs)
                child.FindSiblings();
        }