/// <summary>
        /// Zwraca maksymalny las (maximal forest) w grafie
        /// </summary>
        static PartGraph Forest(PartGraph partGraph)
        {
            var graph = partGraph.Graph;

            List <int> notVisited = new List <int>();

            for (int i = 0; i < graph.VerticesCount; i++)
            {
                notVisited.Add(i);
            }

            HashSet <Edge> edges = new HashSet <Edge>();

            while (notVisited.Count > 0)
            {
                int curNum = notVisited[0];

                notVisited.Remove(curNum);

                foreach (var edge in graph.OutEdges(curNum))
                {
                    edges.Add(new Edge(partGraph.NumbersInOriginal[edge.From], partGraph.NumbersInOriginal[edge.To], edge.Weight));
                    notVisited.Remove(edge.To);
                }
            }

            return(createPartGraphFromEdges(edges));
        }
        // Graf ma być spójny i nieskierowany
        public static PartGraph Camerini(PartGraph partGraph)
        {
            var graph = partGraph.Graph;
            var edges = getGraphEdges(partGraph);

            if (edges.Count == 1)
            {
                return(partGraph);
            }

            // A - waga wieksza lub równa niż w B
            (var A, var B) = setAandB(edges);

            PartGraph GB = createPartGraphFromEdges(B);
            var       F  = Forest(GB);

            if (isSpanningTree(graph, F.Graph))
            {
                return(Camerini(GB));
            }
            else
            {
                var GA = createPartGraphFromEdges(A);

                var       CameriniforGA = Camerini(GA);
                PartGraph ret           = MergeGraphs(CameriniforGA, F);

                return(ret);
            }
        }
 static void printGraph(PartGraph GB, string comment)
 {
     Console.WriteLine($"Graph number: {++graphNum}");
     Console.WriteLine(comment);
     foreach (var x in GB.NumbersInOriginal)
     {
         Console.WriteLine($"{x.Key} : {x.Value}");
     }
     Console.WriteLine();
 }
        /// <summary>
        /// Łączy dwa PartGrafy, zwracając PartGraf, będący sumą. Etykiety wierzchołków są zgodne z etykietami w oryginalnym grafie.
        /// </summary>
        static PartGraph MergeGraphs(PartGraph A, PartGraph B)
        {
            HashSet <Edge> edges = new HashSet <Edge>();

            foreach (var e in getGraphEdges(A).ToArray())
            {
                edges.Add(e);
            }

            foreach (var e in getGraphEdges(B).ToArray())
            {
                edges.Add(e);
            }

            return(createPartGraphFromEdges(edges));
        }
        /// <summary>
        /// Zwraca kolejkę krawędzi, oznaczonych numeracją grafu oryginalnego
        /// </summary>
        static EdgesMaxPriorityQueue getGraphEdges(PartGraph partGraph)
        {
            var graph = partGraph.Graph;
            EdgesMaxPriorityQueue edges = new EdgesMaxPriorityQueue();

            int verticesCount = graph.VerticesCount;

            for (int i = 0; i < verticesCount; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    if (!double.IsNaN(graph.GetEdgeWeight(i, j)))
                    {
                        edges.Put(new Edge(partGraph.NumbersInOriginal[i], partGraph.NumbersInOriginal[j], graph.GetEdgeWeight(i, j)));
                    }
                }
            }
            return(edges);
        }