Given a weighted undirected graph represented using an adjacency list adj[][], where each adj[u] contains pairs of the form {v, w}, indicating that vertex u is connected to vertex v with an edge weight w. Find the distance of the second best Minimum Spanning Tree (MST) of this graph.
A second best MST is defined as the minimum-weight spanning tree whose total weight is strictly greater than the weight of the minimum spanning tree, but as small as possible. If no such spanning tree exists, return -1.
The idea is that we will first run Kruskal’s algorithm to build the MST and record all its edges. Now, to search for the second best MST, we try removing each MST edge one by one. For every removed edge, we run Kruskal again on the remaining edges, which forces the algorithm to pick a different edge to reconnect the graph. This produces a new spanning tree that differs from the original MST by exactly one edge. Among all these candidate trees, we take the one with the smallest total weight that is still greater than the original MST weight.
C++
#include<iostream>#include<vector>#include<algorithm>#include<climits>usingnamespacestd;classDSU{public:vector<int>p,r;// initially each node is its own parentDSU(intn):p(n),r(n,0){for(inti=0;i<n;i++)p[i]=i;}// path compressionintfind(intx){returnp[x]==x?x:p[x]=find(p[x]);}boolunite(inta,intb){a=find(a);b=find(b);// already connectedif(a==b)returnfalse;// union by rankif(r[a]<r[b])swap(a,b);p[b]=a;if(r[a]==r[b])r[a]++;returntrue;}};// run kruskal while skipping one MST edgeintkruskal(intn,vector<array<int,3>>&edges,intskipU,intskipV){DSUdsu(n);intcost=0,used=0;for(auto&e:edges){intu=e[0],v=e[1],w=e[2];// ignore the chosen MST edgeif((u==skipU&&v==skipV)||(u==skipV&&v==skipU))continue;if(dsu.unite(u,v)){cost+=w;used++;}}// not a valid treeif(used!=n-1)returnINT_MAX;returncost;}intsecondBestMST(vector<vector<pair<int,int>>>&adj){intn=adj.size();// convert adjacency list to edge listvector<array<int,3>>edges;for(intu=0;u<n;u++){for(auto&p:adj[u]){intv=p.first,w=p.second;// avoid duplicate undirected edgesif(u<v)edges.push_back({u,v,w});}}// sort edges by weight oncesort(edges.begin(),edges.end(),[](auto&a,auto&b){returna[2]<b[2];});// build the MSTDSUdsu(n);intmstCost=0;vector<array<int,3>>mstEdges;for(auto&e:edges){if(dsu.unite(e[0],e[1])){mstCost+=e[2];mstEdges.push_back(e);}}// try removing each MST edge to find second bestintsecondBest=INT_MAX;for(auto&e:mstEdges){intnewCost=kruskal(n,edges,e[0],e[1]);if(newCost>mstCost&&newCost<secondBest)secondBest=newCost;}returnsecondBest==INT_MAX?-1:secondBest;}intmain(){vector<vector<pair<int,int>>>adj={{{1,4},{2,3}},{{0,4},{2,1},{3,5}},{{0,3},{1,1},{3,7},{4,10}},{{1,5},{2,7},{4,2}},{{2,10},{3,2}}};cout<<secondBestMST(adj)<<"\n";return0;}
Java
//Driver Code Startsimportjava.util.ArrayList;classDSU{publicint[]p,r;// initially each node is its own parentDSU(intn){p=newint[n];r=newint[n];for(inti=0;i<n;i++)p[i]=i;}// path compressionintfind(intx){returnp[x]==x?x:(p[x]=find(p[x]));}booleanunite(inta,intb){a=find(a);b=find(b);// already connectedif(a==b)returnfalse;// union by rankif(r[a]<r[b]){intt=a;a=b;b=t;}p[b]=a;if(r[a]==r[b])r[a]++;returntrue;}}classGFG{//Driver Code Ends// run kruskal while skipping one MST edgestaticintkruskal(intn,ArrayList<int[]>edges,intskipU,intskipV){DSUdsu=newDSU(n);intcost=0,used=0;for(int[]e:edges){intu=e[0],v=e[1],w=e[2];// ignore the chosen MST edgeif((u==skipU&&v==skipV)||(u==skipV&&v==skipU))continue;if(dsu.unite(u,v)){cost+=w;used++;}}// not a valid treeif(used!=n-1)returnInteger.MAX_VALUE;returncost;}staticintsecondBestMST(ArrayList<ArrayList<int[]>>adj){intn=adj.size();// convert adjacency list to edge listArrayList<int[]>edges=newArrayList<>();for(intu=0;u<n;u++){for(int[]p:adj.get(u)){intv=p[0],w=p[1];// avoid duplicate undirected edgesif(u<v)edges.add(newint[]{u,v,w});}}// sort edges by weight onceedges.sort((a,b)->a[2]-b[2]);// build the MSTDSUdsu=newDSU(n);intmstCost=0;ArrayList<int[]>mstEdges=newArrayList<>();for(int[]e:edges){if(dsu.unite(e[0],e[1])){mstCost+=e[2];mstEdges.add(e);}}// try removing each MST edge to find second bestintsecondBest=Integer.MAX_VALUE;for(int[]e:mstEdges){intnewCost=kruskal(n,edges,e[0],e[1]);if(newCost>mstCost&&newCost<secondBest)secondBest=newCost;}returnsecondBest==Integer.MAX_VALUE?-1:secondBest;}//Driver Code StartsstaticvoidaddEdge(ArrayList<ArrayList<int[]>>adj,intu,intv,intw){adj.get(u).add(newint[]{v,w});adj.get(v).add(newint[]{u,w});}publicstaticvoidmain(String[]args){intV=5;ArrayList<ArrayList<int[]>>adj=newArrayList<>();for(inti=0;i<V;i++)adj.add(newArrayList<>());addEdge(adj,0,1,4);addEdge(adj,0,2,3);addEdge(adj,1,2,1);addEdge(adj,1,3,5);addEdge(adj,2,3,7);addEdge(adj,2,4,10);addEdge(adj,3,4,2);System.out.println(secondBestMST(adj));}}//Driver Code Ends
Python
#Driver Code StartsclassDSU:def__init__(self,n):# initially each node is its own parentself.p=list(range(n))self.r=[0]*n# path compressiondeffind(self,x):ifself.p[x]==x:returnxself.p[x]=self.find(self.p[x])returnself.p[x]defunite(self,a,b):a=self.find(a)b=self.find(b)# already connectedifa==b:returnFalse# union by rankifself.r[a]<self.r[b]:a,b=b,aself.p[b]=aifself.r[a]==self.r[b]:self.r[a]+=1returnTrue#Driver Code Ends# run kruskal while skipping one MST edgedefkruskal(n,edges,skipU,skipV):dsu=DSU(n)cost=0used=0foru,v,winedges:# ignore the chosen MST edgeif(u==skipUandv==skipV)or(u==skipVandv==skipU):continueifdsu.unite(u,v):cost+=wused+=1# not a valid treeifused!=n-1:returnfloat("inf")returncostdefsecondBestMST(adj):n=len(adj)# convert adjacency list to edge listedges=[]foruinrange(n):forv,winadj[u]:# avoid duplicate undirected edgesifu<v:edges.append([u,v,w])# sort edges by weight onceedges.sort(key=lambdax:x[2])# build the MSTdsu=DSU(n)mstCost=0mstEdges=[]foru,v,winedges:ifdsu.unite(u,v):mstCost+=wmstEdges.append([u,v,w])# try removing each MST edge to find second bestsecondBest=float("inf")foru,v,winmstEdges:newCost=kruskal(n,edges,u,v)ifmstCost<newCost<secondBest:secondBest=newCostreturn-1ifsecondBest==float("inf")elsesecondBest#Driver Code Startsif__name__=='__main__':adj=[[(1,4),(2,3)],[(0,4),(2,1),(3,5)],[(0,3),(1,1),(3,7),(4,10)],[(1,5),(2,7),(4,2)],[(2,10),(3,2)]]print(secondBestMST(adj))#Driver Code Ends
C#
//Driver Code StartsusingSystem;usingSystem.Collections.Generic;classDSU{publicint[]p,r;// initially each node is its own parentpublicDSU(intn){p=newint[n];r=newint[n];for(inti=0;i<n;i++)p[i]=i;}// path compressionpublicintfind(intx){returnp[x]==x?x:(p[x]=find(p[x]));}publicboolunite(inta,intb){a=find(a);b=find(b);// already connectedif(a==b)returnfalse;// union by rankif(r[a]<r[b]){intt=a;a=b;b=t;}p[b]=a;if(r[a]==r[b])r[a]++;returntrue;}}classGFG{//Driver Code Ends// run kruskal while skipping one MST edgestaticintkruskal(intn,List<int[]>edges,intskipU,intskipV){DSUdsu=newDSU(n);intcost=0,used=0;foreach(vareinedges){intu=e[0],v=e[1],w=e[2];// ignore the chosen MST edgeif((u==skipU&&v==skipV)||(u==skipV&&v==skipU))continue;if(dsu.unite(u,v)){cost+=w;used++;}}// not a valid treeif(used!=n-1)returnint.MaxValue;returncost;}staticintsecondBestMST(List<List<int[]>>adj){intn=adj.Count;// convert adjacency list to edge listList<int[]>edges=newList<int[]>();for(intu=0;u<n;u++){foreach(varpinadj[u]){intv=p[0],w=p[1];// avoid duplicate undirected edgesif(u<v)edges.Add(newint[]{u,v,w});}}// sort edges by weight onceedges.Sort((a,b)=>a[2].CompareTo(b[2]));// build the MSTDSUdsu=newDSU(n);intmstCost=0;List<int[]>mstEdges=newList<int[]>();foreach(vareinedges){if(dsu.unite(e[0],e[1])){mstCost+=e[2];mstEdges.Add(e);}}// try removing each MST edge to find second bestintsecondBest=int.MaxValue;foreach(vareinmstEdges){intnewCost=kruskal(n,edges,e[0],e[1]);if(newCost>mstCost&&newCost<secondBest)secondBest=newCost;}returnsecondBest==int.MaxValue?-1:secondBest;}//Driver Code StartsstaticvoidaddEdge(List<List<int[]>>adj,intu,intv,intw){adj[u].Add(newint[]{v,w});adj[v].Add(newint[]{u,w});}staticvoidMain(){intV=5;// adjacency listvaradj=newList<List<int[]>>();for(inti=0;i<V;i++)adj.Add(newList<int[]>());addEdge(adj,0,1,4);addEdge(adj,0,2,3);addEdge(adj,1,2,1);addEdge(adj,1,3,5);addEdge(adj,2,3,7);addEdge(adj,2,4,10);addEdge(adj,3,4,2);Console.WriteLine(secondBestMST(adj));}}//Driver Code Ends
JavaScript
//Driver Code StartsclassDSU{constructor(n){// initially each node is its own parentthis.p=Array(n).fill(0).map((_,i)=>i);this.r=Array(n).fill(0);}// path compressionfind(x){if(this.p[x]===x)returnx;returnthis.p[x]=this.find(this.p[x]);}unite(a,b){a=this.find(a);b=this.find(b);// already connectedif(a===b)returnfalse;// union by rankif(this.r[a]<this.r[b])[a,b]=[b,a];this.p[b]=a;if(this.r[a]===this.r[b])this.r[a]++;returntrue;}}//Driver Code Ends// run kruskal while skipping one MST edgefunctionkruskal(n,edges,skipU,skipV){letdsu=newDSU(n);letcost=0,used=0;for(let[u,v,w]ofedges){// ignore the chosen MST edgeif((u===skipU&&v===skipV)||(u===skipV&&v===skipU))continue;if(dsu.unite(u,v)){cost+=w;used++;}}// not a valid treeif(used!==n-1)returnInfinity;returncost;}functionsecondBestMST(adj){letn=adj.length;// convert adjacency list to edge listletedges=[];for(letu=0;u<n;u++){for(let[v,w]ofadj[u]){// avoid duplicate undirected edgesif(u<v)edges.push([u,v,w]);}}// sort edges by weight onceedges.sort((a,b)=>a[2]-b[2]);// build the MSTletdsu=newDSU(n);letmstCost=0;letmstEdges=[];for(leteofedges){if(dsu.unite(e[0],e[1])){mstCost+=e[2];mstEdges.push(e);}}// try removing each MST edge to find second bestletsecondBest=Infinity;for(leteofmstEdges){letnewCost=kruskal(n,edges,e[0],e[1]);if(newCost>mstCost&&newCost<secondBest)secondBest=newCost;}returnsecondBest===Infinity?-1:secondBest;}//Driver Code Starts// Driver Codeletadj=[[[1,4],[2,3]],[[0,4],[2,1],[3,5]],[[0,3],[1,1],[3,7],[4,10]],[[1,5],[2,7],[4,2]],[[2,10],[3,2]]];console.log(secondBestMST(adj));//Driver Code Ends
Output
12
Time Complexity: O(V * E), We sort the edges once in O(E log E) and build the MST in O(E). Then for each of the V−1 MST edges, we rerun Kruskal without that edge, each taking O(E). So the extra work is O(V *E), which dominates everything. Auxiliary Space: O(V + E)