/// <summary>
        /// kruskal's algorithm
        /// </summary>
        /// <param name="g"></param>
        public KruskalMST(EdgeWeightedGraph g)
        {
            //more efficient to build heap by passing array of edges
            MinHeap <Edge> pq = new MinHeap <Edge>();

            foreach (Edge e in g.Edges())
            {
                pq.Insert(e);
            }

            //rum greedy algorithm
            UF uf = new UF(g.V);

            while (!pq.IsEmpty() && mst.Count < g.V - 1)
            {
                Edge e = pq.Pop();
                int  v = e.Either();
                int  w = e.Other(v);
                if (!uf.IsConnected(v, w))
                {
                    //v-w does not create a cycle
                    uf.Union(v, w);
                    mst.Enqueue(e);
                    weight += e.Weight();
                }
            }
        }
        /// <summary>
        /// check optimality conditions (takes time proportional EVlgV)
        /// </summary>
        /// <param name="g"></param>
        /// <returns></returns>
        public bool Check(EdgeWeightedGraph g)
        {
            //check total weight
            double total = 0.0;

            foreach (var edge in Edges())
            {
                total += edge.Weight();
            }

            double EPSILON = 1E-12;

            if (System.Math.Abs(total - Weight()) > EPSILON)
            {
                //weight of edges must equal to weight()
                return(false);
            }

            //check that it is acyclic
            UF uf = new UF(g.V);

            foreach (var edge in Edges())
            {
                int v = edge.Either();
                int w = edge.Other(v);
                if (uf.IsConnected(v, w))
                {
                    return(false);
                }
                uf.Union(w, v);
            }

            //check that it is a spanning forest
            foreach (var edge in Edges())
            {
                int v = edge.Either();
                int w = edge.Other(v);
                if (!uf.IsConnected(w, v))
                {
                    return(false);
                }
            }

            //check that is is a minimal spanning forest(cut optimality conditions0
            foreach (var edge in Edges())
            {
                int v = edge.Either();
                int w = edge.Other(v);

                //all edges in mst except e
                uf = new UF(g.V);
                foreach (var f in mst)
                {
                    int x = f.Either();
                    int y = f.Other(x);
                    if (f != edge)
                    {
                        uf.Union(x, y);
                    }
                }

                foreach (var f in g.Edges())
                {
                    int x = f.Either();
                    int y = f.Other(x);

                    if (!uf.IsConnected(x, y))
                    {
                        if (f.Weight() < edge.Weight())
                        {
                            return(false);
                        }
                    }
                }
            }

            return(true);
        }