static void Main(string[] args)
        {
            var processorNum = int.Parse(Console.ReadLine());
            var jobNum       = int.Parse(Console.ReadLine());

            var jobs = new Job[jobNum];

            for (var i = 0; i < jobNum; i++)
            {
                var jobDesc = Console.ReadLine().Split(' ');
                jobs[i] = new Job(jobDesc[0], double.Parse(jobDesc[1]));
            }

            Array.Sort(jobs);

            var processors = new MinPQ <Processor>(processorNum);

            for (var i = 0; i < processorNum; i++)
            {
                processors.Insert(new Processor());
            }

            for (var i = jobs.Length - 1; i >= 0; i--)
            {
                var min = processors.DelMin();
                min.Add(jobs[i]);
                processors.Insert(min);
            }

            while (!processors.IsEmpty())
            {
                Console.WriteLine(processors.DelMin());
            }
        }
Beispiel #2
0
        /// <summary>
        /// Returns a uniformly random tree on <tt>V</tt> vertices.
        /// This algorithm uses a Prufer sequence and takes time proportional to <em>V log V</em>.
        /// http://www.proofwiki.org/wiki/Labeled_Tree_from_Prüfer_Sequence
        /// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.36.6484&rep=rep1&type=pdf
        /// </summary>
        /// <param name="v">V the number of vertices in the tree</param>
        /// <returns>a uniformly random tree on <tt>V</tt> vertices</returns>
        public static Graph Tree(int v)
        {
            var g = new Graph(v);

            // special case
            if (v == 1)
            {
                return(g);
            }

            // Cayley's theorem: there are V^(V-2) labeled trees on V vertices
            // Prufer sequence: sequence of V-2 values between 0 and V-1
            // Prufer's proof of Cayley's theorem: Prufer sequences are in 1-1
            // with labeled trees on V vertices
            var prufer = new int[v - 2];

            for (var i = 0; i < v - 2; i++)
            {
                prufer[i] = StdRandom.Uniform(v);
            }

            // degree of vertex v = 1 + number of times it appers in Prufer sequence
            var degree = new int[v];

            for (var vi = 0; vi < v; vi++)
            {
                degree[vi] = 1;
            }
            for (var i = 0; i < v - 2; i++)
            {
                degree[prufer[i]]++;
            }

            // pq contains all vertices of degree 1
            var pq = new MinPQ <Integer>();

            for (var vi = 0; vi < v; vi++)
            {
                if (degree[vi] == 1)
                {
                    pq.Insert(vi);
                }
            }

            // repeatedly delMin() degree 1 vertex that has the minimum index
            for (var i = 0; i < v - 2; i++)
            {
                int vmin = pq.DelMin();
                g.AddEdge(vmin, prufer[i]);
                degree[vmin]--;
                degree[prufer[i]]--;
                if (degree[prufer[i]] == 1)
                {
                    pq.Insert(prufer[i]);
                }
            }
            g.AddEdge(pq.DelMin(), pq.DelMin());
            return(g);
        }
Beispiel #3
0
 public void Min_pq_delete_tests()
 {
     var p = new MinPQ<int>(5);
     p.Insert(5);
     p.Insert(4);
     p.Insert(99);
     p.Insert(14);
     p.Insert(0);
     Assert.AreEqual(0, p.DelMin());
     Assert.AreEqual(4, p.DelMin());
     Assert.AreEqual(5, p.DelMin());
     Assert.AreEqual(14, p.DelMin());
     Assert.AreEqual(99, p.DelMin());
 }
Beispiel #4
0
        public Kruskal(WeightedGraph G)
        {
            var V  = G.V();
            var uf = new QuickUnion(V);

            var pq = new MinPQ <Edge>();

            mst = new List <Edge>();
            foreach (Edge e in G.edges())
            {
                pq.Enqueue(e);
            }

            while (!pq.IsEmpty && mst.Count < V - 1)
            {
                var e = pq.DelMin();
                var v = e.either();
                var w = e.other(v);

                if (!uf.IsConnected(v, w))
                {
                    uf.Union(v, w);
                    mst.Add(e);
                }
            }
        }
Beispiel #5
0
        private readonly Collections.Queue <EdgeW> _mst = new Collections.Queue <EdgeW>(); // edges in MST

        /// <summary>
        /// Compute a minimum spanning tree (or forest) of an edge-weighted graph.
        /// </summary>
        /// <param name="g">g the edge-weighted graph</param>
        public KruskalMST(EdgeWeightedGraph g)
        {
            // more efficient to build heap by passing array of edges
            var pq = new MinPQ <EdgeW>();

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

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

            while (!pq.IsEmpty() && _mst.Size() < g.V - 1)
            {
                var e = pq.DelMin();
                var v = e.Either();
                var w = e.Other(v);
                if (!uf.Connected(v, w))
                {                    // v-w does not create a cycle
                    uf.Union(v, w);  // merge v and w components
                    _mst.Enqueue(e); // add edge e to mst
                    _weight += e.Weight;
                }
            }

            // check optimality conditions
            //assert check(G);
        }
Beispiel #6
0
        public KruskalMst(EdgeWeightedGraph graph)
        {
            mst = new Queue <Edge>();

            var prioryQueue = new MinPQ <Edge>();

            foreach (var edge in graph.GetEdges())
            {
                prioryQueue.Insert(edge);
            }

            var ds = new DisjointSet(graph.Vertices);

            while (!prioryQueue.IsEmpty() && mst.Count < graph.Vertices - 1)
            {
                var edge        = prioryQueue.DelMin();
                int vertex      = edge.Either();
                int otherVertex = edge.Other(vertex);

                if (ds.Connected(vertex, otherVertex))
                {
                    continue;
                }

                ds.Union(vertex, otherVertex);
                mst.Enqueue(edge);
            }
        }
Beispiel #7
0
        public LazyPrimMST(EdgeWeightedGraph graph)
        {
            prioryQueue = new MinPQ <Edge>();
            marked      = new bool[graph.Vertecies];
            mst         = new Queue <Edge>();

            Visit(graph, 0);

            while (!prioryQueue.IsEmpty())
            {
                var edge        = prioryQueue.DelMin();
                int vertex      = edge.Either();
                int otherVertex = edge.Other(vertex);

                if (marked[vertex] && marked[otherVertex])
                {
                    continue;
                }

                mst.Enqueue(edge);
                if (!marked[vertex])
                {
                    Visit(graph, vertex);
                }
                if (!marked[otherVertex])
                {
                    Visit(graph, otherVertex);
                }
            }
        }
Beispiel #8
0
        public KruskalMST(EdgeWeightedGraph ewg)
        {
            this.g   = ewg;
            minPQ    = new MinPQ <Edge>(g.E());
            mstEdges = new Queue <Edge>();
            //first we need to create a priority queue to store all Edges

            int either, other;

            foreach (Edge edge in ewg.Edges())
            {
                //either = edge.Either();
                //other = edge.Other(either);
                //if(either<other) //insert the same edge once only when either<other;
                minPQ.Insert(edge);
            }
            Edge currrent;

            Utils.UF uf = new Utils.UF(g.V()); //instantiate the union find variable

            //second, we take min from the PQ one at a time and insert to the queue if both ends are not connected yet
            while (!minPQ.IsEmpty() && mstEdges.Count < (this.g.V() - 1))
            {
                currrent = minPQ.DelMin();
                either   = currrent.Either();
                other    = currrent.Other(either);
                if (!uf.IsConnected(either, other)) //only add the edge into the final queue if both ends are not connected
                {
                    mstEdges.Enqueue(currrent);
                    uf.Union(either, other);
                }
            }
        }
Beispiel #9
0
        /// <summary>
        /// Compute a minimum spanning tree (or forest) of an edge-weighted graph.
        /// </summary>
        /// <param name="g">g the edge-weighted graph</param>
        public KruskalMST(EdgeWeightedGraph g)
        {
            // more efficient to build heap by passing array of edges
            var pq = new MinPQ<EdgeW>();
            foreach (var e in g.Edges())
            {
                pq.Insert(e);
            }

            // run greedy algorithm
            var uf = new UF(g.V);
            while (!pq.IsEmpty() && _mst.Size() < g.V - 1)
            {
                var e = pq.DelMin();
                var v = e.Either();
                var w = e.Other(v);
                if (!uf.Connected(v, w))
                { // v-w does not create a cycle
                    uf.Union(v, w);  // merge v and w components
                    _mst.Enqueue(e);  // add edge e to mst
                    _weight += e.Weight;
                }
            }

            // check optimality conditions
            //assert check(G);
        }
Beispiel #10
0
        public void PQTest()
        {
            var tested = new MinPQ <int>(30);;

            // tested.insert(30);
            // var min = tested.delMin();
            tested.Insert(10);
            tested.Insert(20);
            tested.Insert(30);
            tested.Insert(5);
            tested.Insert(1);
            Assert.Equal(1, tested.DelMin());
            Assert.Equal(5, tested.DelMin());
            Assert.Equal(10, tested.DelMin());
            Assert.Equal(20, tested.DelMin());
        }
        public KruskalMST(EdgeWeightedGraph G)
        {
            _mst = new Queue <Edge>();
            var pq = new MinPQ <Edge>(G.Edges().Count());
            var uf = new WeightedQuickUnion(G.V);

            foreach (var edge in G.Edges())
            {
                if (edge is null)
                {
                    continue;
                }
                pq.Insert(edge);
            }
            while (!pq.IsEmpty && _mst.Count() < G.V - 1)
            {
                var e = pq.DelMin(); // Get min weight edge on pq
                var v = e.Either();
                var w = e.Other(v);  // and its vertices.
                if (uf.Connected(v, w))
                {
                    continue;    // Ignore ineligible edges.
                }
                uf.Union(v, w);  // Merge components.
                _mst.Enqueue(e); // Add edge to mst.
            }
        }
        static void Main(string[] args)
        {
            // 输入格式: buy 20.05 100
            var buyer  = new MaxPQ <Ticket>();
            var seller = new MinPQ <Ticket>();

            var n = int.Parse(Console.ReadLine());

            for (var i = 0; i < n; i++)
            {
                var ticket = new Ticket();
                var item   = Console.ReadLine().Split(' ');

                ticket.Price = double.Parse(item[1]);
                ticket.Share = int.Parse(item[2]);
                if (item[0] == "buy")
                {
                    buyer.Insert(ticket);
                }
                else
                {
                    seller.Insert(ticket);
                }
            }

            while (!buyer.IsEmpty() && !seller.IsEmpty())
            {
                if (buyer.Max().Price < seller.Min().Price)
                {
                    break;
                }
                var buy  = buyer.DelMax();
                var sell = seller.DelMin();
                Console.Write("sell $" + sell.Price + " * " + sell.Share);
                if (buy.Share > sell.Share)
                {
                    Console.WriteLine(" -> " + sell.Share + " -> $" + buy.Price + " * " + buy.Share + " buy");
                    buy.Share -= sell.Share;
                    buyer.Insert(buy);
                }
                else if (buy.Share < sell.Share)
                {
                    sell.Share -= buy.Share;
                    seller.Insert(sell);
                    Console.WriteLine(" -> " + buy.Share + " -> $" + buy.Price + " * " + buy.Share + " buy");
                }
                else
                {
                    Console.WriteLine(" -> " + sell.Share + " -> $" + buy.Price + " * " + buy.Share + " buy");
                }
            }
        }
Beispiel #13
0
        // Relax(u, v, w):
        // if(d[v] > d[u] + w(u, v))
        //    d[v] = d[u] + w(u, v)

        private void dijkstra(EdgeWeightedDigraph graph, int vertex)
        {
            pq.Insert(vertex, 0.0);

            while (!pq.IsEmpty())
            {
                int v = pq.DelMin();
                foreach (DirectedWeightedEdge edge in graph.Adj(v))
                {
                    Relax(edge);
                }
            }
        }
Beispiel #14
0
        public void TestMinPQ() {
            var arr = CreateRandomArray(10);
            Insertion<int>.Sort(arr);
            StdOut.WriteLine(arr);

            var pq = new MinPQ<int>();
            foreach (int i in arr) {
                pq.Insert(i);
            }

            while (!pq.IsEmpty) {
                StdOut.WriteLine("delete min: {0}", pq.DelMin());
            }
        }
Beispiel #15
0
        /// <summary>
        /// 进行一次测试。
        /// </summary>
        /// <param name="m">测试使用的 m 值。</param>
        /// <param name="n">测试使用的 n 值。</param>
        /// <returns></returns>
        static long test(int m, int n)
        {
            var pq = new MinPQ <EuclideanDistance3D>(m);

            int[]  x      = new int[n];
            int[]  y      = new int[n];
            int[]  z      = new int[n];
            Random random = new Random();

            for (int i = 0; i < n; i++)
            {
                x[i] = random.Next();
                y[i] = random.Next();
                z[i] = random.Next();
            }

            Stopwatch sw = new Stopwatch();

            sw.Start();// 开始计时
            for (int i = 0; i < m; i++)
            {
                // 先插入 m 个记录
                pq.Insert(new EuclideanDistance3D(x[i], y[i], z[i]));
            }
            for (int i = m; i < n; i++)
            {
                // 插入剩余 n-m 个记录
                pq.DelMin();
                pq.Insert(new EuclideanDistance3D(x[i], y[i], z[i]));
            }
            while (pq.IsEmpty())
            {
                pq.DelMin();
            }
            sw.Stop();// 停止计时
            return(sw.ElapsedMilliseconds);
        }
Beispiel #16
0
        void PriorityQueueTest()
        {
            var strArr = FileHandler.ReadFileAsStrArr("words3.txt");
            var qp     = new MinPQ <string>(strArr.Length);

            foreach (var item in strArr)
            {
                qp.Insert(item);
            }
            while (!qp.IsEmpty())
            {
                Console.WriteLine(qp.DelMin());
            }
            Console.ReadKey();
        }
Beispiel #17
0
        public void ShouldReturnSmallestKeyInTheQueue(int[] values, int[] expectedOrder)
        {
            // Arrange
            var minPQ = new MinPQ <int>(values);

            foreach (var expected in expectedOrder)
            {
                // Act
                var actualMin       = minPQ.Min();
                var actualMinDelete = minPQ.DelMin();

                // Assert
                Assert.AreEqual(actualMin, actualMinDelete);
                Assert.AreEqual(expected, actualMin);
            }
        }
Beispiel #18
0
 public PrimMSTLazy(EdgeWeightedGraph g, int v)
 {
     _mstQueue = new Queue<Edge>();
     _minPQ = new MinPQ<Edge>();
     _marked = new bool[g.V()];
     Scan(g, v);
     while (_mstQueue < (g.V() -1))
     {
         var e = _minPQ.DelMin();
         var v1 = e.Either;
         var v2 = e.TheOther(v2);
         if(_marked[v1] && _marked[v2]) continue;
         _mstQueue.Enqueue(e);
         if(_marked[v1] == false) Scan(g, v1);
         if(_marked[v2] == false) Scan(g, v2};
     }
 }
Beispiel #19
0
        public void TestMinPQ()
        {
            MinPQ <int> pq = new MinPQ <int>();

            for (var i = 0; i < 100; ++i)
            {
                pq.Enqueue(99 - i);
            }
            Assert.Equal(100, pq.Count);
            Assert.False(pq.IsEmpty);
            for (var i = 0; i < 100; ++i)
            {
                Assert.Equal(i, pq.DelMin());
                Assert.Equal(99 - i, pq.Count);
            }
            Assert.True(pq.IsEmpty);
        }
Beispiel #20
0
 public LazyPrimMST(EdgeWeightedGraph g)
 {
     _marked = new bool[g.V];
     _mst    = new NodeQueue <Edge>();
     pq      = new MinPQ <Edge>(g.E);//MinPQ没有实现自动调整大小,先将就着用吧。
     Visit(g, 0);
     while (!pq.IsEmpty())
     {
         var e = pq.DelMin();
         var v = e.Either();
         v = !_marked[v] ? v : e.Other(v);//至少会有一条边已在生成树中。
         if (!_marked[v])
         {
             _mst.Enqueue(e);
             Visit(g, v);
         }
     }
 }
Beispiel #21
0
        private void AstarSP(EdgeWeightedDigraph graph, int vertex, int target)
        {
            pq.Insert(vertex, 0.0);

            while (!pq.IsEmpty())
            {
                int v = pq.DelMin();

                if (v == target)
                {
                    break;
                }

                foreach (DirectedWeightedEdge edge in graph.Adj(v))
                {
                    Relax(edge, target);
                }
            }
        }
Beispiel #22
0
        public void TestMinPQ()
        {
            var arr = CreateRandomArray(10);

            Insertion <int> .Sort(arr);

            StdOut.WriteLine(arr);

            var pq = new MinPQ <int>();

            foreach (int i in arr)
            {
                pq.Insert(i);
            }

            while (!pq.IsEmpty)
            {
                StdOut.WriteLine("delete min: {0}", pq.DelMin());
            }
        }
Beispiel #23
0
        public KruskalMST(EdgeWeightedGraph g)
        {
            MinPQ<Edge> pq = new MinPQ<Edge>();
            foreach (Edge e in g.Edges())
                pq.Insert(e);

            Part1.QuickUnion uf = new Part1.QuickUnion(g.V());
            while (!pq.IsEmpty() && this._mst.Count < g.V() - 1)
            {
                Edge e = pq.DelMin();
                int v = e.Either();
                int w = e.Other(v);
                if (!uf.IsConnected(v, w))
                {
                    uf.Union(v, w);
                    this._mst.Enqueue(e);
                    this.Weight += e.Weight();
                }
            }
        }
Beispiel #24
0
 public void Simulate(double limit, double Hz)
 {
     _pq = new MinPQ <CollisionEvent>(1000);
     for (int i = 0; i < _particles.Length; i++)
     {
         PredictCollisions(_particles[i], limit);
     }
     _pq.Insert(new CollisionEvent(0, null, null));
     while (_pq.Count > 0)
     {
         CollisionEvent collisionEvent = _pq.DelMin();
         if (!collisionEvent.IsValid())
         {
             continue;
         }
         for (int i = 0; i < _particles.Length; i++)
         {
             _particles[i].Move(collisionEvent.Time - t);
         }
         t = collisionEvent.Time;
         Particle a = collisionEvent.A, b = collisionEvent.B;
         if (a != null && b != null)
         {
             a.BounceOff(b);
         }
         else if (a != null && b == null)
         {
             a.BounceOffVerticalWall();
         }
         else if (a == null && b != null)
         {
             b.BounceOffHorizontalWall();
         }
         else if (a == null && b == null)
         {
             ReDraw(limit, Hz);
         }
         PredictCollisions(a, limit);
         PredictCollisions(b, limit);
     }
 }
Beispiel #25
0
        public LazyPrimMST(EdgeWeightedGraph ewg)
        {
            g = ewg;
            int vertexNum = g.V();
            int edgeNum   = g.E();

            isVisited = new bool[vertexNum];
            minQueue  = new MinPQ <Edge>(edgeNum);
            mstEdges  = new Queue <Edge>();

            Visit(0);

            Edge eCurrent;
            int  either, other;

            while (!minQueue.IsEmpty())
            {
                eCurrent = minQueue.DelMin();
                either   = eCurrent.Either();
                other    = eCurrent.Other(either);
                if (!isVisited[either] || !isVisited[other]) //at least one end of the edge should not be visited, otherwise we will have a loop
                {
                    mstEdges.Enqueue(eCurrent);
                    if (!isVisited[either])
                    {
                        Visit(either);
                    }
                    else
                    {
                        Visit(other);
                    }
                }
            }
            //for(int i=0;i<vertexNum;i++)
            //{
            //    if(!isVisisted[i])
            //    {

            //    }
            //}
        }
Beispiel #26
0
        public LazyPrim(WeightedGraph G)
        {
            var V = G.V();

            marked = new bool[V];
            pq     = new MinPQ <Edge>();

            var s = 0;

            foreach (var e in G.adj(s))
            {
                pq.Enqueue(e);
            }

            mst = new List <Edge>();

            while (!pq.IsEmpty && mst.Count < V - 1)
            {
                var e = pq.DelMin();
                var v = e.either();
                var w = e.other(v);

                if (marked[v] && marked[w])
                {
                    continue;
                }

                mst.Add(e);

                if (!marked[v])
                {
                    visit(G, v);
                }
                if (!marked[w])
                {
                    visit(G, w);
                }
            }
        }
Beispiel #27
0
        static void Main(string[] args)
        {
            int n = 1000000;

            MinPQ <CubeSum> pq = new MinPQ <CubeSum>();

            Console.WriteLine("正在初始化");
            for (int i = 0; i <= n; i++)
            {
                pq.Insert(new CubeSum(i, i));
            }

            FileStream   ostream = new FileStream("./result.txt", FileMode.Create, FileAccess.Write);
            StreamWriter sw      = new StreamWriter(ostream);

            Console.WriteLine("正在写入文件……");
            CubeSum prev      = new CubeSum(-1, -1);
            long    pairCount = 0;

            while (!pq.IsEmpty())
            {
                CubeSum s = pq.DelMin();
                if (s.sum == prev.sum)
                {
                    sw.WriteLine(s + " = " + prev.i + "^3 + " + prev.j + "^3");
                    pairCount++;
                }
                if (s.j < n)
                {
                    pq.Insert(new CubeSum(s.i, s.j + 1));
                }
                prev = s;
            }
            sw.WriteLine("共找到" + pairCount + "对数据");
            Console.WriteLine("共找到" + pairCount + "对数据");
            sw.Close();
            Console.WriteLine("结果已经保存到程序所在目录下的 result.txt 文件中");
        }
Beispiel #28
0
        public void MinPQTest()
        {
            MinPQ <Edge> minQ;
            int          edgeNum, vNum;

            //Build minQueue
            using (StreamReader sr = new StreamReader(@"E:\Study\ALG2017\ALGRKC\dataSelf\tinyEWG.txt"))
            {
                string line = null;
                line = sr.ReadLine(); // read V;
                string[] pair = line.Split();
                vNum    = Int32.Parse(line);
                line    = sr.ReadLine();
                edgeNum = Int32.Parse(line);

                minQ = new MinPQ <Edge>(edgeNum);

                //while((line=sr.ReadLine())!=null)   //each line is an edge
                for (int i = 0; i < edgeNum; i++)
                {
                    line = sr.ReadLine();
                    pair = line.Split();
                    int    v      = Int32.Parse(pair[0]);
                    int    w      = Int32.Parse(pair[1]);
                    double weight = Double.Parse(pair[2]);
                    Edge   e      = new Edge(v, w, weight);

                    minQ.Insert(e);
                }
            }

            for (int i = 0; i < edgeNum; i++)
            {
                Edge e = minQ.DelMin();
                Console.WriteLine(e.ToString());
            }
        }
Beispiel #29
0
 /// <summary>
 /// run Prim's algorithm
 /// </summary>
 /// <param name="g"></param>
 /// <param name="s"></param>
 private void Prim(EdgeWeightedGraph g, int s)
 {
     Scan(g, s);
     while (!_pq.IsEmpty())
     {                                       // better to stop when mst has V-1 edges
         var e = _pq.DelMin();               // smallest edge on pq
         int v = e.Either(), w = e.Other(v); // two endpoints
         //assert marked[v] || marked[w];
         if (_marked[v] && _marked[w])
         {
             continue;                               // lazy, both v and w already scanned
         }
         _mst.Enqueue(e);                            // add e to MST
         _weight += e.Weight;
         if (!_marked[v])
         {
             Scan(g, v);                            // v becomes part of tree
         }
         if (!_marked[w])
         {
             Scan(g, w);                            // w becomes part of tree
         }
     }
 }
        /// <summary>
        /// Returns a uniformly random tree on <tt>V</tt> vertices.
        /// This algorithm uses a Prufer sequence and takes time proportional to <em>V log V</em>.
        /// http://www.proofwiki.org/wiki/Labeled_Tree_from_Prüfer_Sequence
        /// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.36.6484&rep=rep1&type=pdf
        /// </summary>
        /// <param name="v">V the number of vertices in the tree</param>
        /// <returns>a uniformly random tree on <tt>V</tt> vertices</returns>
        public static Graph Tree(int v)
        {
            var g = new Graph(v);

            // special case
            if (v == 1) return g;

            // Cayley's theorem: there are V^(V-2) labeled trees on V vertices
            // Prufer sequence: sequence of V-2 values between 0 and V-1
            // Prufer's proof of Cayley's theorem: Prufer sequences are in 1-1
            // with labeled trees on V vertices
            var prufer = new int[v - 2];
            for (var i = 0; i < v - 2; i++)
                prufer[i] = StdRandom.Uniform(v);

            // degree of vertex v = 1 + number of times it appers in Prufer sequence
            var degree = new int[v];
            for (var vi = 0; vi < v; vi++)
                degree[vi] = 1;
            for (var i = 0; i < v - 2; i++)
                degree[prufer[i]]++;

            // pq contains all vertices of degree 1
            var pq = new MinPQ<Integer>();
            for (var vi = 0; vi < v; vi++)
                if (degree[vi] == 1) pq.Insert(vi);

            // repeatedly delMin() degree 1 vertex that has the minimum index
            for (var i = 0; i < v - 2; i++)
            {
                int vmin = pq.DelMin();
                g.AddEdge(vmin, prufer[i]);
                degree[vmin]--;
                degree[prufer[i]]--;
                if (degree[prufer[i]] == 1) pq.Insert(prufer[i]);
            }
            g.AddEdge(pq.DelMin(), pq.DelMin());
            return g;
        }