Prerequisites – Graph, Spanning tree, Disjoint Set (Union – Find).
A minimum spanning tree (MST) T, for a given graph G, spans over all vertices of a given graph and has minimum weight sum of all edges, out of all the possible spanning trees.
Second best MST, T’, is a spanning tree with the second minimum weight sum of all edges, out of all spanning trees of graph G.
T and T’ differ by only one edge replacement. So, we should find an edge enew which is not in T and replace it with an edge in T (say eold) such that T’ = T union {enew} – {eold} is a spanning tree and weight difference of (enew – eold) is minimum (enew, eold are edges in the graph G).
Using Kruskal’s Algorithm –
- Use Kruskal’s algorithm to find MST T of graph G. Remove a single edge from it and replace it with another to obtain T’.
- Sort the edges in O(ElogE) time (E-no.of edges) and find MST using Kruskal’s algorithm in O(E) time (No.of edges in MST = V-1 where V = no.of vertices in the graph G).
- For each edge in MST, temporarily exclude it from the edge list (so that we cannot choose it).
- Then, try to find MST in O(E) using the remaining edges. (no need to sort again)
- Repeat the above for all edges in MST and take the best one. (with 2nd minimum weight sum). Thus, we obtained T’ – second-best MST.
- Overall Time Complexity – O(ElogE + E +VE) = O(VE)
Below is the implementation of the above approach:
// C++ implementation to find the // second best MST #include <bits/stdc++.h> using namespace std;
// used to implement union-find algorithm int parent[100005];
// to keep track of edges in MST vector< int > present;
// to keep track of number of edges // in spanning trees other than the MST int edg;
// a structure to represent a // weighted edge in graph struct edge {
int src, dest, weight;
} edges[100005]; // array edges is of type edge. // Compare two edges according // to their weights. // Used in sort() for sorting // an array of edges bool cmp(edge x, edge y)
{ return x.weight < y.weight;
} // initialising the array - // each vertex is its own parent // initially void initialise( int n)
{ // 1-indexed
for ( int i = 1; i <= n; i++)
parent[i] = i;
} // Implementing the union-find algorithm int find( int x)
{ if (parent[x] == x)
return x;
return parent[x] = find(parent[x]);
} // Function to find the union // for the Minimum spanning Tree int union1( int i, int sum)
{ int x, y;
x = find(edges[i].src);
y = find(edges[i].dest);
if (x != y) {
// parent of x = y (LCA) -
// both are edge connected
parent[x] = y;
// keeping track of edges in MST
present.push_back(i);
// finding sum of weights
// of edges in MST
sum += edges[i].weight;
}
return sum;
} // Function to find the second // best minimum spanning Tree int union2( int i, int sum)
{ int x, y;
x = find(edges[i].src);
y = find(edges[i].dest);
if (x != y) {
// parent of x = y (LCA) -
// both are edge connected
parent[x] = y;
// sum of weights of edges
// in spanning tree
sum += edges[i].weight;
edg++;
}
return sum;
} // Driver Code int main()
{ // V-> Number of vertices,
// E-> Number of edges
int V, E;
V = 5;
E = 8;
// initialising the array to
// be used for union-find
initialise(V);
// src, dest and weights can
// also be taken from user as
// input the following vectors
// represent - source[0],
// destination[0] are connected
// by an edge with
// weight[0]
vector< int > source = { 1, 3, 2, 3,
2, 5, 1, 3 };
vector< int > destination = { 3, 4, 4,
2, 5, 4, 2, 5 };
vector< int > weights = { 75, 51, 19,
95, 42, 31, 9, 66 };
for ( int i = 0; i < E; i++) {
edges[i].src = source[i];
edges[i].dest = destination[i];
edges[i].weight = weights[i];
}
// sorting the array of edges
// based on edge weights
sort(edges, edges + E, cmp);
int sum = 0;
for ( int i = 0; i < E; i++) {
sum = union1(i, sum);
}
// printing the cost of MST
cout << "MST: " << sum << "\n" ;
// initialising cost of second best MST
int sec_best_mst = INT_MAX;
// setting the sum to zero again.
sum = 0;
int j;
for (j = 0; j < present.size(); j++) {
initialise(V);
edg = 0;
for ( int i = 0; i < E; i++) {
// excluding one edge of
// MST at a time
// and forming spanning tree
// with remaining
// edges
if (i == present[j])
continue ;
sum = union2(i, sum);
}
// checking if number of edges = V-1 or not
// since number of edges in a spanning tree of
// graph with V vertices is (V-1)
if (edg != V - 1) {
sum = 0;
continue ;
}
// storing the minimum sum
// in sec_best_mst
if (sec_best_mst > sum)
sec_best_mst = sum;
sum = 0;
}
// printing the cost of second best MST
cout << "Second Best MST: "
<< sec_best_mst << "\n" ;
return 0;
} |
// Java implementation to find the // second best MST import java.util.*;
public class Main {
// used to implement union-find algorithm
static int [] parent = new int [ 100005 ];
// to keep track of edges in MST
static List<Integer> present = new ArrayList<>();
// to keep track of number of edges
// in spanning trees other than the MST
static int edg;
static class Edge implements Comparable<Edge> {
int src, dest, weight;
Edge( int src, int dest, int weight) {
this .src = src;
this .dest = dest;
this .weight = weight;
}
@Override
// array edges is of type edge.
// Compare two edges according
// to their weights.
// Used in sort() for sorting
// an array of edges
public int compareTo(Edge other) {
return this .weight - other.weight;
}
}
// initialising the array -
// each vertex is its own parent
// initially
static void initialise( int n) {
// 1-indexed
for ( int i = 1 ; i <= n; i++)
parent[i] = i;
}
// Implementing the union-find algorithm
static int find( int x) {
if (parent[x] == x)
return x;
return parent[x] = find(parent[x]);
}
// Function to find the union
// for the Minimum spanning Tree
static int union1( int i, int sum, Edge[] edges) {
int x, y;
x = find(edges[i].src);
y = find(edges[i].dest);
if (x != y) {
// parent of x = y (LCA) -
// both are edge connected
parent[x] = y;
// keeping track of edges in MST
present.add(i);
sum += edges[i].weight;
}
return sum;
}
// Function to find the second
// best minimum spanning Tree
static int union2( int i, int sum, Edge[] edges) {
int x, y;
x = find(edges[i].src);
y = find(edges[i].dest);
if (x != y) {
// parent of x = y (LCA) -
// both are edge connected
parent[x] = y;
// sum of weights of edges
// in spanning tree
sum += edges[i].weight;
edg++;
}
return sum;
}
// Driver Code
public static void main(String[] args) {
// V-> Number of vertices,
// E-> Number of edges
int V = 5 , E = 8 ;
// initialising the array to
// be used for union-find
initialise(V);
// src, dest and weights can
// also be taken from user as
// input the following vectors
// represent - source[0],
// destination[0] are connected
// by an edge with
// weight[0]
int [] source = { 1 , 3 , 2 , 3 , 2 , 5 , 1 , 3 };
int [] destination = { 3 , 4 , 4 , 2 , 5 , 4 , 2 , 5 };
int [] weights = { 75 , 51 , 19 , 95 , 42 , 31 , 9 , 66 };
Edge[] edges = new Edge[E];
for ( int i = 0 ; i < E; i++) {
edges[i] = new Edge(source[i], destination[i], weights[i]);
}
// sorting the array of edges
// based on edge weights
Arrays.sort(edges);
int sum = 0 ;
for ( int i = 0 ; i < E; i++) {
sum = union1(i, sum, edges);
}
// printing the cost of MST
System.out.println( "MST: " + sum);
// initialising cost of second best MST
int sec_best_mst = Integer.MAX_VALUE;
// setting the sum to zero again.
sum = 0 ;
int j;
for (j = 0 ; j < present.size(); j++) {
initialise(V);
edg = 0 ;
for ( int i = 0 ; i < E; i++) {
// excluding one edge of
// MST at a time
// and forming spanning tree
// with remaining
// edges
if (i == present.get(j))
continue ;
sum = union2(i, sum, edges);
}
// checking if number of edges = V-1 or not
// since number of edges in a spanning tree of
// graph with V vertices is (V-1)
if (edg != V - 1 ) {
sum = 0 ;
continue ;
}
// storing the minimum sum
// in sec_best_mst
if (sec_best_mst > sum)
sec_best_mst = sum;
sum = 0 ;
}
// printing the cost of second best MST
System.out.println( "Second Best MST: " + sec_best_mst);
}
} // This code is contributed by princekumaras |
# Python implementation to find the # second best MST # used to implement union-find algorithm parent = [i for i in range ( 100005 )]
# to keep track of edges in MST present = []
# to keep track of number of edges # in spanning trees other than the MST edg = 0
# a structure to represent a # weighted edge in graph class Edge:
def __init__( self , src, dest, weight):
self .src = src
self .dest = dest
self .weight = weight
# array edges is of type edge. # Compare two edges according # to their weights. # Used in sorted() for sorting # an array of edges def cmp (x, y):
return x.weight < y.weight
# initialising the array - # each vertex is its own parent # initially def initialise(n):
# 1-indexed
for i in range ( 1 , n + 1 ):
parent[i] = i
# Implementing the union-find algorithm def find(x):
if parent[x] = = x:
return x
parent[x] = find(parent[x])
return parent[x]
# Function to find the union # for the Minimum spanning Tree def union1(i, sum ):
global edg
x = find(edges[i].src)
y = find(edges[i].dest)
if x ! = y:
# parent of x = y (LCA) -
# both are edge connected
parent[x] = y
# keeping track of edges in MST
present.append(i)
# finding sum of weights
# of edges in MST
sum + = edges[i].weight
return sum
# Function to find the second # best minimum spanning Tree def union2(i, sum ):
global edg
x = find(edges[i].src)
y = find(edges[i].dest)
if x ! = y:
# parent of x = y (LCA) -
# both are edge connected
parent[x] = y
# sum of weights of edges
# in spanning tree
sum + = edges[i].weight
edg + = 1
return sum
# Driver Code if __name__ = = "__main__" :
# V-> Number of vertices,
# E-> Number of edges
V = 5
E = 8
# initialising the array to # be used for union-find initialise(V)
# src, dest and weights can # also be taken from user as # input the following vectors # represent - source[0], # destination[0] are connected # by an edge with # weight[0] source = [ 1 , 3 , 2 , 3 , 2 , 5 , 1 , 3 ]
destination = [ 3 , 4 , 4 , 2 , 5 , 4 , 2 , 5 ]
weights = [ 75 , 51 , 19 , 95 , 42 , 31 , 9 , 66 ]
# create a list of Edge objects
edges = [Edge( 0 , 0 , 0 ) for _ in range (E)]
# fill in the values for each edge for i in range (E):
edges[i].src = source[i]
edges[i].dest = destination[i]
edges[i].weight = weights[i]
# sorting the array of edges # based on edge weights edges = sorted (edges, key = lambda x: x.weight)
sum = 0
for i in range (E):
sum = union1(i, sum )
# printing the cost of MST print ( "MST: " , sum )
# sorting the array of edges # based on edge weights edges = sorted (edges, key = lambda x: x.weight)
# initialising cost of second best MST sec_best_mst = float ( 'inf' )
# setting the sum to zero again. sum = 0
j = 0
while j < len (present):
initialise(V)
edg = 0
i = 0
while i < E:
# excluding one edge of
# MST at a time
# and forming spanning tree
# with remaining
# edges
if i = = present[j]:
i + = 1
continue
sum = union2(i, sum )
i + = 1
# checking if number of edges = V-1 or not
# since number of edges in a spanning tree of
# graph with V vertices is (V-1)
if edg ! = V - 1 :
sum = 0
j + = 1
continue
# storing the minimum sum
# in sec_best_mst
if sec_best_mst > sum :
sec_best_mst = sum
sum = 0
j + = 1
# printing the cost of second best MST print ( "Second Best MST: " , sec_best_mst)
|
// C# code addition using System;
using System.Collections.Generic;
using System.Linq;
class MainClass
{ // used to implement union-find algorithm
static int [] parent = new int [100005];
// to keep track of edges in MST
static List < int > present = new List < int > ();
// to keep track of number of edges
// in spanning trees other than the MST
static int edg;
class Edge: IComparable < Edge > {
public int src,
dest,
weight;
public Edge( int src, int dest, int weight) {
this .src = src;
this .dest = dest;
this .weight = weight;
}
public int CompareTo(Edge other) {
return this .weight - other.weight;
}
}
// initialising the array -
// each vertex is its own parent
// initially
static void initialise( int n) {
// 1-indexed
for ( int i = 1; i <= n; i++)
parent[i] = i;
}
// Implementing the union-find algorithm
static int find( int x) {
if (parent[x] == x)
return x;
return parent[x] = find(parent[x]);
}
// Function to find the union
// for the Minimum spanning Tree
static int union1( int i, int sum, Edge[] edges) {
int x, y;
x = find(edges[i].src);
y = find(edges[i].dest);
if (x != y) {
// parent of x = y (LCA) -
// both are edge connected
parent[x] = y;
// keeping track of edges in MST
present.Add(i);
sum += edges[i].weight;
}
return sum;
}
// Function to find the second
// best minimum spanning Tree
static int union2( int i, int sum, Edge[] edges) {
int x, y;
x = find(edges[i].src);
y = find(edges[i].dest);
if (x != y) {
// parent of x = y (LCA) -
// both are edge connected
parent[x] = y;
// sum of weights of edges
// in spanning tree
sum += edges[i].weight;
edg++;
}
return sum;
}
// Driver Code
public static void Main( string [] args) {
int V = 5, E = 8;
// initialising the array to
// be used for union-find
initialise(V);
// src, dest and weights can
// also be taken from user as
// input the following vectors
// represent - source[0],
// destination[0] are connected
// by an edge with
// weight[0]
int [] source = {1,3,2,3,2,5,1,3};
int [] destination = {3,4,4,2,5,4,2,5};
int [] weights = {75,51,19,95,42,31,9,66};
Edge[] edges = new Edge[E];
for ( int i = 0; i < E; i++) {
edges[i] = new Edge(source[i], destination[i], weights[i]);
}
// sorting the array of edges
// based on edge weights
Array.Sort(edges);
int sum = 0;
for ( int i = 0; i < E; i++) {
sum = union1(i, sum, edges);
}
// printing the cost of MST
Console.WriteLine( "MST: " + sum);
// initialising cost of second best MST
int sec_best_mst = int .MaxValue;
// setting the sum to zero again.
sum = 0;
int j;
for (j = 0; j < present.Count; j++) {
initialise(V);
edg = 0;
for ( int i = 0; i < E; i++) {
// excluding one edge of
// MST at a time
// and forming spanning tree
// with remaining
// edges
if (i == present[j])
continue ;
sum = union2(i, sum, edges);
}
// checking if number of edges = V-1 or not
// since number of edges in a spanning tree of
// graph with V vertices is (V-1)
if (edg != V - 1) {
sum = 0;
continue ;
}
// storing the minimum sum
// in sec_best_mst
if (sec_best_mst > sum)
sec_best_mst = sum;
sum = 0;
}
// printing the cost of second best MST
Console.WriteLine( "Second Best MST: " + sec_best_mst);
}
} // The code is contributed by Nidhi goel. |
// JavaScript implementation to find the // second best MST // used to implement union-find algorithm let parent = []; // to keep track of edges in MST let present = []; // to keep track of number of edges // in spanning trees other than the MST let edg; // a structure to represent a // weighted edge in graph function Edge(src, dest, weight) {
this .src = src;
this .dest = dest;
this .weight = weight;
} // array edges is of type edge. // Compare two edges according // to their weights. // Used in sort() for sorting // an array of edges function cmp(x, y) {
return x.weight - y.weight;
} // initialising the array - // each vertex is its own parent // initially function initialise(n) {
// 1-indexed
for (let i = 1; i <= n; i++) {
parent[i] = i;
}
} // Implementing the union-find algorithm function find(x) {
if (parent[x] === x) {
return x;
}
return parent[x] = find(parent[x]);
} // Function to find the union // for the Minimum spanning Tree function union1(i, sum) {
let x = find(edges[i].src);
let y = find(edges[i].dest);
if (x !== y) {
// parent of x = y (LCA) -
// both are edge connected
parent[x] = y;
// keeping track of edges in MST
present.push(i);
// finding sum of weights
// of edges in MST
sum += edges[i].weight;
}
return sum;
} // Function to find the second // best minimum spanning Tree function union2(i, sum) {
let x = find(edges[i].src);
let y = find(edges[i].dest);
if (x !== y) {
// parent of x = y (LCA) -
// both are edge connected
parent[x] = y;
// sum of weights of edges
// in spanning tree
sum += edges[i].weight;
edg++;
}
return sum;
} // Driver Code // V-> Number of vertices, // E-> Number of edges
let V = 5; let E = 8; // initialising the array to
// be used for union-find
initialise(V); // src, dest and weights can
// also be taken from user as
// input the following vectors
// represent - source[0],
// destination[0] are connected
// by an edge with
// weight[0]
let source = [1, 3, 2, 3, 2, 5, 1, 3]; let destination = [3, 4, 4, 2, 5, 4, 2, 5]; let weights = [75, 51, 19, 95, 42, 31, 9, 66]; let edges = new Array(E);
for (let i = 0; i < E; i++) {
edges[i] = new Edge(source[i], destination[i], weights[i]);
} // sorting the array of edges
// based on edge weights
edges.sort(cmp); let sum = 0; for (let i = 0; i < E; i++) {
sum = union1(i, sum);
} // printing the cost of MST console.log( "MST: " + sum);
// initialising cost of second best MST let sec_best_mst = Infinity; // setting the sum to zero again.
sum = 0; let j; for (j = 0; j < present.length; j++) {
initialise(V);
edg = 0;
for (let i = 0; i < E; i++) {
// excluding one edge of
// MST at a time
// and forming spanning tree
// with remaining
// edges
if (i === present[j]) {
continue ;
}
sum = union2(i, sum);
}
// checking if number of edges = V-1 or not
// since number of edges in a spanning tree of
// graph with V vertices is (V-1)
if (edg !== V - 1) {
sum = 0;
continue ;
}
// storing the minimum sum
// in sec_best_mst
if (sec_best_mst > sum) {
sec_best_mst = sum;
}
sum = 0;
} // printing the cost of second best MST console.log( "Second Best MST: " + sec_best_mst);
|
MST: 110 Second Best MST: 121
Time Complexity – O(VE) where V – number of vertices in the input graph, E – number of edges in the input graph.