0% found this document useful (0 votes)
23 views41 pages

mik final

The document discusses the concept of minimum spanning trees in undirected and simple graphs, detailing foundational graph theory concepts, relevant algorithms like Kruskal’s and Prim’s, and methods to list all minimum spanning trees. It outlines approaches such as divide and conquer and cut-set based algorithms, along with their time complexities. The document also includes practical implementations of depth-first search (DFS) and breadth-first search (BFS) algorithms for finding spanning trees.

Uploaded by

AshishYadav
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views41 pages

mik final

The document discusses the concept of minimum spanning trees in undirected and simple graphs, detailing foundational graph theory concepts, relevant algorithms like Kruskal’s and Prim’s, and methods to list all minimum spanning trees. It outlines approaches such as divide and conquer and cut-set based algorithms, along with their time complexities. The document also includes practical implementations of depth-first search (DFS) and breadth-first search (BFS) algorithms for finding spanning trees.

Uploaded by

AshishYadav
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 41

Listing all the minimum spanning trees in

an undirected and simple graph

Under the guidance of

Dr. Bhawani Shankar Panda


Department of Mathematics,
Indian Institute of Technology Delhi

Submitted by :-

Atul Kumar
2015MAS7065

Mohammad Irshad Khan


2015MAS7082
Preface
We are very thankful to Dr. Bhawani Shankar Panda under whom we did our
project. He always supported us, for completing our project effectively and moreover on
time .He gave his time for discussion despite of his busy schedules.
Last but not the least, we would like to thank our classmates who helped us lot, time to
time.

Thanks

Atul kumar
Mohd. Irshad Khan
Content

● Abstract

1. Minimum Spanning Trees


1.1 Tree
1.2 Spanning Tree
1.2.1 Matrix Tree Theorem
1.2.2 Breadth First Search (BFS)
1.2.3 Depth First Search (BFS)
1.3 Minimum Spanning Tree
1.3.1 Kruskal’s Algorithm
1.3.2 Prim’s Algorithm

2. Time Complexity

3. Listing all the minimum spanning trees in an undirected and simple


graph
3.1 Divide and conquer approach
3.2 Cut­set based algorithm
3.3 Further Improvement

● Reference
Abstract

First we will go through the basic concepts of graph theory that is relevant to our study
which are trees, spanning trees and minimum spanning trees. Then we will get a
glimpse on algorithms to find spanning trees in an undirected and simple graph, known
as breadth first search (BFS) and depth first search (DFS), algorithms to find minimum
spanning trees known as Prim’s and Kruskal’s algorithm. Then we will move to our
main aim to find all the minimum spanning tree in an undirected and simple graph. We
first encounter the divide and conquer approach to achieve it which has time complexity
of O(N (mn + n2 log n)). Then we explore this algorithm using cut­set where we come to
the concepts of substitute, and it would become of O(Nmn). Finally we study the
improvement in the cut­set based algorithm to find the substitute in a better way which
has time complexity of O(Nm log n).
1. Minimum Spanning Trees

1.1 Tree

Definition : A graph G = ( V , E ) is called a tree if G is connected and acyclic.

The following theorem captures many important facts about trees.

Theorem : ( Characterizations of trees )


Let G = ( V , E ) be an undirected graph having n vertices and m edges. The following
statements are equivalent.

1. G is a tree.
2. There is a unique path between any two vertices in G.
3. G is connected but G­e is disconnected for every edge e of G.
4. G is connected and m = n­1.
5. G is acyclic and m = n­1.
6. G is acyclic but G+xy is cyclic for every x,y ∈ V with xy ∉ E.

Proof : (1)⇒(2) : Since every tree is connected, there is at least one path between any two
vertices in G . Hence, to show that there is a unique path between any two vertices in G, we
have to show that there is at most one path between any two vertices in G. We prove this by
contradiction. So, assume that there are at least two paths between some pair of vertices, say
between x and y. Let P1∪P2 contains a cycle. So, G contains a cycle. This contradicts the fact
that G is tree . Hence, there is a unique path between any two vertices in G.

(2)⇒(3) : Since, any two vertices in G are connected by a unique path, G is connected .
Let xy be any edge in E. Then, P=xy is a path from x to y. So, it must be unique path from x to y.
If we remove xy from G , then there is no path from x to y. Hence, G­xy is disconnected. Since,
xy is a arbitrary edge of G, G­e is disconnected for every edge e of G. Hence, G is connected but
G­e is disconnected for every edge e of G.
(3)⇒(4) : By assumption, G is connected. So we need only to show that m=n­1 . We prove this
by induction . A connected graph with n=1 or n=2 vertices has n­1 edges. Assume that every
graph with fewer than n vertices satisfying (3) also satisfy (4). Suppose that G has n≥3 vertices
and G satisfies (3), i.e. G is connected but G­e is disconnected for every edge e of G. Let e=xy be
any edge of G. Now, G­e is disconnected and has exactly two connected components. Let G1 and
G2 be the connected components of G. Let ni and mi , 1 ≤ i ≤ 2, be the number of vertices and
edges in Gi , 1 ≤ i ≤ 2. Now, each component satisfies (3), or else G would not satisfy (3). Since, ni
< n, i=1,2
By induction hypothesis, mi = ni ­ 1, 1 ≤ i ≤ 2. So m = m1 + m2 + 1 = n ­ 1. So, by induction
principle, G has exactly n­1 edges.

(4)⇒(5) : We have to show that every connected graph G with n vertices and n­1 edges are
acyclic. We prove this by induction. For n=1,2 and 3,it can be easily checked that all connected
graph with n vertices and n­1 edges are acyclic. Assume that every connected graph with fewer
than n vertices satisfying (4) is acyclic. Let G be a connected graph having n vertices and n­1
edges, since G is connected and has n­1 edges, G has a vertex of degree 1. Let x be a vertex of
degree 1 in G. let G’ = G­x. Now, G’ is connected and has n­1 vertices and n­2 edges. So, by
induction hypothesis, G’ is acyclic. Since x is a degree 1 vertex, x can not be any cycle of G. Since
G’= G­x is acyclic, G must be acyclic. So, by induction,every connected graph with n vertices and
n­1 edges are acyclic.

(5)⇒(6) : Suppose that G is acyclic and that m=n­1. Let Gi , 1≤ i ≤ k be the connected
component of G. Since G is acyclic, Gi is acyclic for 1≤ i ≤ k . Hence, each Gi , 1≤ i ≤ k is a tree.
Let ni and mi, 1≤ i ≤ k be the number of vertices and edges in Gi , 1≤ i ≤ k respectively. Since (1)
implies (5), m = ∑mi = ∑(ni­1) = n­k. So, G must be a tree. Since (1) implies (2), any two vertices
in G are connected by a unique path. Thus, adding any edge to G creates a cycle.

(6)⇒(1) : Suppose that G is acyclic but G+xy is cyclic for every x,y in V with xy ∉ E. We must
show that G is connected. Let u and v be arbitrary vertices in G. If u and v are not already
adjacent, adding the edge uv creates a cycle in which all edges but uv belong to G. Thus, there is
a path from u to v and since u and v were chosen arbitrary, G is connected.
Some example of trees are shown as following :

1.2 Spanning Tree

Definition : A subgraph T = ( V1 , E1 ) of a graph G = ( V , E ) is a spanning tree if


(i) T is a tree, and
(ii) V1 = V

Theorem : A graph admits a spanning tree if and only if G is connected.

Proof : Necessity :
Suppose G admits a spanning tree, say T . We will show that G is connected. Let
u,v be any two arbitrary vertices of G. Since, T is a spanning subgraph of G, u and v are
vertices of T as well. Since, T is connected, there is a path P(u,v) from u to v in T.
As T is a subgraph of G, P(u,v) is also a path in G. Since, u and v are arbitrary vertices of
G, there is a path between any two vertices of G. Hence G is connected.
Sufficiency : Let G be a connected graph with n vertices and m edges. We construct a
spanning tree T of G. Let k=m­n+1. Define Gi , 0 ≤ i ≤ k, recursively, as follows:

Since, Gi has exactly n­1+k­i edges, Gi is cyclic for each i, 0 ≤ i ≤ k­1 . So, each Gi , 0≤
i ≤ k­1 , has a cycle. If Gi­1 is connected, then Gi is also connected, as ei belongs to some
cycle of Gi­1 , 0 ≤ i ≤ k­1 . Hence, Gk is connected and has exactly n­1 edges. So, Gk is a
tree . Let T = Gk , now T is a spanning tree of G.

Some of the examples of spanning trees are shown below :

1.2.1 Matrix Tree Theorem :

Definition : If G(V,E) is a graph on n vertices with V = {v1,...,vn} then its graph Laplacian L is
an n×n matrix whose entries are
Equivalently, L = D­A, where D is a diagonal matrix with Djj = deg(vj) and A is the graph’s
adjacency matrix.

Theorem (Matrix­Tree Theorem) : If G(V,E) is an undirected graph and L is its graph


Laplacian, then the number NT of spanning trees contained in G is given by the following
computation:

(1) Choose a vertex vj and eliminate the jth row and jth column from L to get a new matrix Lj
(2) Compute NT = det(Lj ).

The number NT is the total no. of spanning tree in given Graph G.

Example : The graph Laplacian L of given Graph G in following figure

Now, choose vj =v1, and apply Matrix tree theorem, we get


And the number of tree is

Now, we will discuss two recursive algorithms viz depth­first search and breadth­first
search to find out a spanning tree of a connected, undirected and simple graph.

1.2.2 Depth First Search (DFS) Algorithm

Input : A connected graph G

Step 1 : Choose an arbitrary vertex as root of the tree

Step 2 : Form a path starting at root by successively adding new edge that is incident at
the recently added vertex to the path and the other end point of this newly added edge is
not already present in the path

Step 3 : If the path contains all the edges of the given graph, we are done, otherwise
move back to the next to last vertex in this path and if possible, form a new path starting
at this vertex by adding new edges, whose other endpoints are not already visited. If new
path is not possible at this vertex, then move back further in this path, i.e. two vertices
back in this path and try to form a new path again and so on

Repeat step 3 until all the vertices are visited

Output : A spanning tree of G

Code in C++

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

vector<int> v;

bool is_viewed(vector<int> v,int j)


{
bool flag=false;
for(int i : v)
if(i==j)
{flag=true;break;}
return flag;
}
void do_dfs(int i, int p, vector<vector<int>> a,
vector<vector<int>> &b, int n){
for(int j=0;j<n;j++)
if(a[i][j]==1 && is_viewed(v,j)==false && j!=p)
{
b[i][j]=1;
b[j][i]=1;
v.push_back(j);
do_dfs(j,i,a,b,n);
}
}

int main()
{
int n,m;
cin>>n>>m;
vector< vector<int> > a(n, vector<int>(n) ) ;

for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i][j]=0;

vector< vector<int> > b(n, vector<int>(n) ) ;

for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
b[i][j]=0;

for(int i=0;i<m;i++)
{
int x,y;
cin>>x>>y;
a[x­1][y­1]=1;
a[y­1][x­1]=1;

}
v.push_back(0);
do_dfs(0,­1,a,b,n);

cout<<"\nAns is :\n";
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
cout<<b[i][j]<<" ";
cout<<"\n";
}

return 0;
}

1.2.3 Breadth First Search (BFS) Algorithm

Input : A connected graph G

Step 1 : Choose an arbitrary vertex say a, as root of tree, place it at level 0. Set i=0
Step 2 : For each vertex at level i, add an edge incident to this vertex, if the other
endpoint (other adjacent vertex) of this edge is not already present in the tree. This
produces the vertices at level i+1

Step 3 : If all the vertices of the graph included in the tree, stop here otherwise set
i=i+1 and repeat step 2

Output : A spanning tree of G

Code in C++

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

vector<int> v;

class couple{ public :


int parent;
vector<int> childs;

bool is_viewed(vector<int> v,int j)


{
bool flag=false;
for(int i : v)
if(i==j)
{flag=true;break;}
return flag;
}

int main()
{
int n,m;
cin>>n>>m;
vector<vector<int>> a(n,vector<int>(n)) ;

for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i][j]=0;

vector<vector<int>> b(n,vector<int>(n)) ;

for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
b[i][j]=0;

for(int i=0;i<m;i++)
{
int x,y;
cin>>x>>y;
a[x­1][y­1]=1;
a[y­1][x­1]=1;
}

vector<couple> olds;
vector<couple> news;

couple temp;
temp.parent=­1;
temp.childs.push_back(0);

olds.push_back(temp);
int count=0;

while(count<m){

for(couple node : olds){


for(int i : node.childs){
couple temp2;
temp2.parent=i;

for(int j=0;j<n;j++){
if(a[i][j]==1 && is_viewed(v,j)==true &&
j!=node.parent){
count++;
}
if(a[i][j]==1 && is_viewed(v,j)==false &&
j!=node.parent){
count++;
temp2.childs.push_back(j);
v.push_back(j);
b[i][j]=1;
b[j][i]=1;
}
}

news.push_back(temp2);
}
}

olds.clear();
olds=news;
news.clear();
}

cout<<"\nAns is :\n";
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
cout<<b[i][j]<<" ";
cout<<"\n";
}

return 0;
}
1.3 Minimum Spanning Tree

Let G = ( V , E ) be a connected weighted graph and C be the cost matrix of G. Let T= ( V , E ) be


a spanning tree of G . The cost of T , denoted by C(T), is defined as follows:

Definition : The cost of a spanning tree T= ( V ,E’ ) of a weighted graph G = ( V , E) with cost
matrix C is defined by

Definition : A spanning tree T of a weighted connected graph is called a minimum spanning


tree if C(T) ≤ C(T’) for any other spanning tree T’ of G.

Note that there may be more than one minimum spanning tree of graph. For example, the
graph G in the following figure has exactly two minimum spanning trees.

Now we will discuss two algorithms, viz Prim’s algorithm and Kruskal’s Algorithm to find out
minimum spanning tree for an undirected connected weighted simple graph.
1.3.1 Kruskal’s Algorithm

As we have seen in the previous section that an acyclic graph with n vertices and n­1 edges
is a tree. The first algorithm, known as Kruskal’s Algorithm, uses this fact to construct an MST
of a connected weighted graph G.
We first describe the algorithm informally. First, the algorithm arranges the edges of the
graph G in the non­decreasing order of their costs. It starts with the graph T = ( V , E’), where
E’ = ϕ initially . It then examines each edge for inclusion into the T . If the current edge e under
examination does not form a cycle with the so far selected edges, then the edge e is included in
T. If e forms a cycle with the so far selected edges, then e is rejected. After the decision of
selecting or rejecting the current edge e , the next edge in the list become current edge. The
algorithm terminates once n­1 edges have been selected or there is no edge left for
consideration. The algorithm, thus, maintains acyclicity at each stage of inclusion of edge to T. If
the algorithm is successful in adding n­1 edges to T, then T become a spanning tree of G. Since
the edge are examined for inclusion in the non­decreasing order of costs, T turn out to be an
MST.

Kruskal’s Algorithm

Input : A connected Graph G = ( V , E ) and the cost matrix C of G.


Output : A Minimum spanning tree T = ( V , E’) of G.
Method:
Step 1 : Sort the edge of G in the non­decreasing order of their
costs.
Let the sorted list edges e1,e2,...,em.
Step 2 : T = ( V , E’) , where E’=ϕ. i=1; count=0;
While ( count < n­1 and i < m )
{
if (T= ( V , E’∪{ ei} ) is acyclic)
{E’ = E’∪{ ei}; count = count +1 ;}
i= i+1;
}
Code in C++

//Kruskal's Algorithm

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

bool find_vec(vector<int> v,int j)


{
bool flag=false;
for(int i=0;i<v.size();i++)
if(v.at(i)==j)
{flag=true;break;}
return flag;
}

int main()
{
int n,m;
cin>>n>>m;
int a[n][n];

for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i][j]=0;

int b[n][n];

for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
b[i][j]=0;

vector<int> woe;

for(int i=0;i<m;i++)
{
int x,y,w;
cin>>x>>y>>w;
a[x­1][y­1]=w;
a[y­1][x­1]=w;
woe.push_back(w);

}
vector<int> v;
sort(woe.begin(),woe.end());

int i=0;
while(v.size() < n)
{
bool flag=true;
int temp=woe.at(i);
for(int j=0;j<n­1;j++)
{
for(int k=j+1;k<n;k++)
{
if(a[j][k]==temp)
{
if(find_vec(v,j)==false && find_vec(v,k)==false)
{
flag=false;
b[j][k]=temp;
b[k][j]=temp;
v.push_back(j);
v.push_back(k);
i++;
break;
}
else if(find_vec(v,j)==false)
{
flag=false;
b[j][k]=temp;
b[k][j]=temp;
v.push_back(j);
i++;
break;
}
else if(find_vec(v,k)==false)
{
flag=false;
b[j][k]=temp;
b[k][j]=temp;
v.push_back(k);
i++;
break;
}
else
continue;
}

if(!flag)
break;
}

if(!flag)
break;
}
}

cout<<"\nAns is\n";
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
cout<<b[i][j]<<" ";
cout<<"\n";
}

return 0;
}
1.3.2 Prim’s Algorithm

As we have seen above, Kruskal’s algorithm starts with the vertex set V and empty edge
set and keeps on adding edges maintaining acyclicity throughout. Once n­1 edges are added, it
becomes a tree. Prim’s algorithm adopts a different strategy. It uses the fact that a connected
graph with n vertices and n­1 edges is a tree. It starts with vertex set V’ = {v} where v is any
arbitrary vertex of G and E’, where E’=Φ. it then selects a least cost edge e = xy with x∈V’ and
y∈V­V’. thus , it maintains throughout that G’ = ( V’ , E’ ) is connected. Once V’ = V, G’ becomes
a spanning tree of G. We next describe the algorithm formally.

Prim’s algorithm

Input : A connected Graph G = ( V , E ) and the cost matrix C of G.

Output : A Minimum spanning tree T = ( V , E’ ) of G.

Method :
{
Step 1 : Let u be any arbitrary vertex of G.
T = ( V’ , E’ ), where V’ ={u} and E’=Φ.
Step 2 : while ( V’≠V )
{
Choose a least cost edge from V’ to V­V’.
Let e = xy be a least cost edge such that x∈V’ and
y∈V­V’.
V’ = V’∪{y};
E’ = E’∪{e};

}
}

Code in C++

#include<iostream>
#include<vector>
using namespace std;

bool find_vec(vector<int> v,int j)


{
bool flag=false;
for(int i=0;i<v.size();i++)
if(v.at(i)==j)
{flag=true;break;}
return flag;
}

int main()
{
int n,m;
cin>>n>>m;
int a[n][n];

for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i][j]=0;

int b[n][n];

for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
b[i][j]=0;

for(int i=0;i<m;i++)
{
int x,y,w;
cin>>x>>y>>w;
a[x­1][y­1]=w;
a[y­1][x­1]=w;
}

int s;
cin>>s;
s­­;
vector<int> v;
v.push_back(s);

while(v.size()<n)
{
bool flag=true;
int min1;
int min2;
int i;
for(int k=0;k<v.size();k++)
{
i=v.at(k);
int j=0;
for(;j<n && flag;j++)
if(a[i][j]!=0 && find_vec(v,j)==false)
{flag=false;min1=i;min2=j;break;}

for(;j<n;j++)
if(a[i][j]!=0 && a[min1][min2]>a[i][j] &&
find_vec(v,j)==false)
{min1=i;min2=j;}
}
b[min1][min2]=a[min1][min2];
b[min2][min1]=a[min1][min2];
v.push_back(min2);
}

cout<<"\nAns is\n";
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
cout<<b[i][j]<<" ";
cout<<"\n";
}

return 0;
Sample Input :

Sample Output :
2. Time complexity
In computer science, the time complexity of an algorithm quantifies the amount of
time taken by an algorithm to run as a function of the length of the string representing
the input.
Time complexity is commonly estimated by counting the number of elementary
operations performed by the algorithm, where an elementary operation takes a fixed
amount of time to perform. Thus, the amount of time taken and the number of
elementary operations performed by the algorithm differ by at most a constant factor.
Since an algorithm's performance time may vary with different inputs of the same size,
one commonly uses the worst­case time complexity of an algorithm, denoted as T(n),
which is defined as the maximum amount of time taken on any input of size n. Less
common, and usually specified explicitly, is the measure of average­case complexity.

The time complexity of an algorithm is commonly expressed using big O notation, which
excludes coefficients and lower order terms. When expressed this way, the time
complexity is said to be described asymptotically, i.e., as the input size goes to infinity.
For example, if the time required by an algorithm on all inputs of size n is at most 5n3 +
3n for any n (bigger than some n0), the asymptotic time complexity is O(n3). Big O
notation is a mathematical notation that describes the limiting behavior of a function
when the argument tends towards a particular value or infinity.

Formal definition of Big O notation

Let f and g be two functions defined on some subset of the real numbers. One writes

That is, f(x) = O(g(x)) if and only if there exists a positive real number M and a real
number x0 such that
In typical usage, the formal definition of O notation is not used directly; rather, the O
notation for a function f is derived by the following simplification rules:

● If f(x) is a sum of several terms, if there is one with largest growth rate, it can
be kept, and all others omitted.
● If f(x) is a product of several factors, any constants (terms in the product that
do not depend on x) can be omitted.

Example

Let f(x) = 6x4 − 2x3 + 5, and suppose we wish to simplify this function, using O notation,
to describe its growth rate as x approaches infinity. This function is the sum of three
terms: 6x4, −2x3, and 5. Of these three terms, the one with the highest growth rate is the
one with the largest exponent as a function of x, namely 6x4. Now one may apply the
second rule: 6x4 is a product of 6 and x4 in which the first factor does not depend on x.
Omitting this factor results in the simplified form x4. Thus, we say that f(x) is a "big­oh"
of (x4). Mathematically, we can write f(x) = O(x4). One may confirm this calculation
using the formal definition: let f(x) = 6x4 − 2x3 + 5 and g(x) = x4. Applying the formal
definition from above, the statement that f(x) = O(x4) is equivalent to its expansion,

for some suitable choice of x0 and M and for all x > x0.

To prove this, let x0 = 1 and M = 13. Then, for all x > x0:

and hence f(x) = O(x4).


3. Listing all the minimum spanning trees in an
undirected and simple graph
Let G = (V , E) be an undirected graph with the vertex set V = { v1 , v2 , . . . , vn } and the
edge set E = { e1 , e2 , . . . , em } ⊆ V × V. Each edge e ∈ E is associated with an integer
weight w(e) > 0. We assume that G is connected and simple (i.e. there exist neither
self­loops nor multiple edges). Now further, this weight is denoted as z*, and by MST we
denote an arbitrary spanning tree of this weight. However, there may be more than one
MST.

3.1 Divide and conquer approach


We are concerned with the following problem :

P : List all the MSTs in graph G.

A prototype enumeration algorithm :


Let T = {e1 , . . . , en−1 } be an arbitrary MST in G, which can be obtained by any standard
MST Algorithms. We make use of this MST to divide P into the following set of mutually
disjoint subproblems (i = 1, . . . , n − 1).

P ({e1 , . . . , ei−1 }, {ei }) : List all the MSTs that contain e1 , . . . , ei−1 , but do not
contain ei .
More generally, for a forest F = {e1 , . . . , ek } in G and a set of edges R ⊆ E that is disjoint
with F (i.e. F ∩ R = Φ), a spanning tree T is (F, R)­admissible if it contains all edges of F,
but does not contain those of R. That is, T is (F, R)­admissible if and only if F ⊆ T and
R∩T = Φ. Here we use T to represent a spanning tree, as well as the set of edges
included in that tree. F and R are the sets of fixed and restricted edges, respectively, and
we pose the following problem.

P (F, R) : List all the MSTs which are (F, R)­admissible.


Clearly, P is identical to P (Φ ,Φ).
We note that an (F, R)­admissible spanning tree of the minimum weight can be easily
obtained by slightly modifying the standard MST algorithms. Let An_MST(F, R)
denote the algorithm to do this, that is it accepts F and R as inputs and returns an (F,
R)­admissible spanning tree T*(F, R) of the minimum weight z*(F, R). Kruskal’s or
Prim’s algorithm can be easily tailored for this purpose. If no (F, R)­admissible spanning
tree exists, we take the convention of writing z*(F, R) = ∞.
Then, if z*(F, R) >z*, no MST can be (F, R)­admissible, and hence we terminate
the subproblem P(F, R). Otherwise, we output T*(F, R) as an MST, and make use of this
tree to introduce a set of subproblems in the following way. Let k = |F | and the tree be
represented as T*(F, R) = F ∪ {ek+1 , . . . , en−1 }. For i = k + 1, . . . , n − 1, we define
Fi := F ∪ {ek+1 , . . . , ei−1 }, Ri = R ∪ {ei }.
Here, in case i = k + 1, we interpret {ek+1 , . . . , ei−1 } = Φ and Fi = F . Then, P (F, R) is
divided into a set of mutually disjoint subproblems P (Fi , Ri ), (i = k + 1, . . . , n − 1), and
the problem is solved if we solve all these subproblems. Thus, a prototype algorithm can
be constructed in the divide and conquer technique as follows :

Algorithm All_MST(F,R)

Comment : F is a forest in G, R ⊆ E and F ∩ R = ∅.


Step 1 : Apply An_MST(F, R) to find T*(F, R) and z*(F, R).
Step 2 : If z*(F, R) > z*, return.
Step 3 : Output T (F, R), and for i = k + 1, . . . , n − 1 do
( Define (Fi, Ri) by , and call All_MST(F i , R i ) ).
Example : Consider the graph G of Figure 1, where edge weights are shown in italic.
We start from P0 = P (Φ , Φ), and obtain an MST with z*= 8 (Step 1). From P0 , 5
children are generated (Step 3) as shown in Figure 2, and in total we obtain 6 MSTs
after examining 17 subproblems.

Figure 1

Due to the recursive nature of the algorithm, the subproblems are visited and numbered
in a depth­first fashion. Here, the subproblems where MSTs are found are shaded with
the corresponding MST shown at each shoulder. Details of the subproblems are
summarized in Table 1. Here, in each row we show (F, R) that defines subproblem Pi , its
parent, an (F, R)­admissible minimum spanning tree (if one exists) and the
corresponding weight z*( F, R) of that tree. Underlined edges represent set of newly
fixed edges at each subproblem.In the column ‘MST’, edges within braces are the fixed
edges, and hyphen(­) shows that the subproblem is terminated because z*(F, R) > z*.
Figure 2
The time complexity of the above algorithm can be evaluated as follows. Let N denote
the number of MSTs included in G, and TMST(n, m) be the time required to solve an MST
problem for a graph with n nodes and m edges. Note that each subproblem, including an
MST, produces at most n − 1 children. So the total number of subproblems generated in
All_MST is at most Nn − N + 1 ≈ Nn. In each subproblem, we solve an MST problem,
which requires O(TMST(n, m)) time. Thus, the total time complexity is O(NnTMST(n, m)).
3.2 A cut-set-based algorithm :

Let T be an MST of G, and ‘e’ an arbitrary edge of T. Deleting ‘e’ from T divides the tree
into two connected components with vertexes sets, say V1 and V2 . We introduce the cut-
set induced by e ∈ T as the set of edges with one endpoint in V1 and the other in V2 . If
we define this as Cut(e) = {e’ ∈ E | e’ ∈ (V1 × V2 ) ∪ (V2 × V1 )}, then we have the following
proposition.

Proposition : Let T be an MST and e ∈ T . Then, for an arbitrary edge e ∈ Cut(e),


w(e’ ) ≥ w(e)
That is, e ∈ T is an edge of the minimum weight in Cut(e). For a pair of edges e ∈ T
and e’ ∈ Cut(e)\{e}, T ∪ {e’ }\{e} defines another spanning tree. Let G(e) denote the graph
obtained from G by deleting e. We then have the following.

Theorem : Let T be an MST, e ∈ T and e’≠ e be second minimum in weight in Cut(e).


Then, T’ = T ∪{e’ }\{e} is a minimum spanning tree in G(e) .
Proof : Suppose that T’ is not a minimum spanning tree in G(e) . Then there exists a
pair of edges c ∉ T and d ∈ T such that
(1) T∪{c}\{d} is a spanning tree, and
(2) w(c) < w(d).
̃= T∪{c}\{d} is a spanning tree with w(T
We note that c ∈ Cut(e), otherwise T ̃)<z* ,
contradicting that T is an MST. Thus, we have
w(e) ≤ w(e’)≤ w(c) <w(d).
Let the cycles included in T*∪ {e’},T*∪{c} and T’∪{c} be C0 , C1 and C2 , respectively.
Since C2 = C0 ⊕ C1 (in Boolean sense) and d ∈C2 ,, we have d ∈ C0 , or d ∈ C1 . Define

∗ ′
̂ = { T ∪ {e }\{d}
T
if d ∈ C0
T ∗ ∪ {c}\{d} if d ∈ C0

̂ is a spanning tree with w(T


Then, T ̂) < z*, which is a contradiction.
Corollary : Let T be an MST, e ∈ T and e’≠ e be second minimum in weight in Cut(e). If
w(e) = w(e’), then T∪{e’}\{e} is an MST; otherwise, no MST exists in G(e) .

Corollary : If all the edges of G are of distinct weights, then MST is unique.

Let T be an MST and e ∈ T .We call ẽ ∈ Cut(e) a substitute of e if ẽ ≠ e and w(ẽ) = w(e).
S(e) stands for the set of all substitutes of e, that is,
S(e) := {ẽ ∈ Cut(e) | ẽ ≠ e , w(ẽ) = w(e) }.

On the basis of the above theorem, we can modify All_MST in the following way. At each
subproblem, in addition to the pair of sets (F,R) representing the fixed and restricted
edges, we assume that an (F,R)-admissible MST exists. Let this tree be T . In the
following algorithm, in the ei subproblem P(F,R), for each ei ∈ T \F, we look for a
substitute ẽ i ∈ S(e). If this is found, we obtain T∪ {ẽ i }\{ei } as a new MST, and use this to
generate a sub-subproblem. Then, the algorithm is described as follows.

Algorithm : All_MST𝟏 (F,R,T)


𝜎̅
Comment : T is an (F,R)-admissible MST, which is written as T = F∪ {ek+1 , … , en }, with
F = {e1 , . . . , ek }.
Step 1: For i = k + 1, . . . , n − 1, do the following:
• Find the cut-set Cut(ei ).
• Find, if one exists, a substitute ẽ i ∈ S(ei ).
Step 2: For i = k + 1, . . . , n − 1, if ẽ i exists do the following:
• Set Ti = T∪ {ẽ i }\{ei } and output Ti . {Comment: A new MST is found}
• Set Fi = F∪ {ek+1 , … , en }, and R i := R ∪ {ei }.
• Call All_MST1 (Fi , R i , Ti ) recursively.

Example : For the graph of Figure 1, Figure 3 shows the behaviour of All_MST1 , where
details of the generated subproblems are summarized in Table 2. In addition to the
information given in Table 1, here is a substitute for the newly restricted edges (∆R) in
each subproblem. In this algorithm, each subproblem generated includes an (F,R)-
admissible MST as shown in Figure 3, and newly fixed edges (∆F) are underlined in
Table 2.

Figure 3

Computational complexity of this algorithm


Cut(ei ) can be found in O(m) time. At each subproblem, this is repeated at most n times.
The running time of All_ MST1 is O(Nmn).
3.3. A further improvement
In the previous section, it took O(m) time, in the worst case, to find a substitute ẽi for
each ei ∈ T. This computation was carried out for each ei from scratch, and the
computation of all substitutes took O(mn) time. In this section, we present an algorithm
that finds ẽi one­by­one, from the reduced set of possible cut­set edges for ei , and after
completing step i this information is carried on to the next step. We try to make the size
of this set as small as possible, and as a result, in total we obtain the set of all substitutes
{ ẽi | ei ∈ T \F} in O(m log n) time, instead of O(mn) in All_MST1.

To accomplish this, at each subproblem P(F , R) with an (F , R)­admissible MST T, we


renumber vertices in postorder fashion as we traverse T from an arbitrary ‘root’ vertex.
Let the vertices thus renumbered be {vi | i = 1,...,n}. Then, T is a tree rooted at vn and by
ei we denote the tree edge connecting vi to its parent vertex. (See Figure 4, where T is
shown in bold). Associated with vi is an interval [σ1i , σ2i], which represents the set of
descendants of this vertex, that is,

j ∈ [σ1i , σ2i] ⇔ vj is a descendant of vi in tree T rooted at vn .……………...(7)

Let Ei := {(vi , vj) ∈ E | (vi , vj) ∉ T} be a set of non­tree edges incident on node vi , and Q
be a set of elements of the form (w, v, v) ∈ Z × V × V.
Here, (w, v, v) ∈ Q means that the edge e = (v, v) ∈ E has weight w(e) = w, and is a
candidate of a cut­set edge at this, and subsequent, stage. We call Q the set of quasi­cuts,
and assume that it is lexicographically ordered with respect to w and v. For ei ∈ T \F, we
make use of Q to find its substitute ẽi and update it for the next i in the following way :

Algorithm Substitute(F , R, T)
Step 1: Set Q := ∅.
Step 2: For i = 1 to n − 1 do the following.
(1) For ∀e = (vi , vj ) ∈ Ei \ R do either of the following
(a) If j<σi1 , {Comment: Reverse the direction}
• If (w(e), j, i) ∈ Q, delete it from Q
• Insert (w(e), i, j ) into Q
(b) If j ∈ [σ1i , σ2i],
• If (w(e), j, i) ∈ Q, delete it from Q
(c) If j > σi2 ,
• Insert (w(e), i, j ) into Q

(2) If ei ∉ F do the following


(a) Find (w, i’, j’) ∈ Q such that w = w(ei) and i’ ∈ [σ1i , σ2i]
(b) If such an (w, i’, j’) is found with j’ ∈ [σ1i , σ2i],
• Delete (w, i’, j’) from Q, and go to (2)­(a)
(c) If such an (w, i’, j’) is found with j’ ∈ [σ1i , σ2i],
• Set ẽi := (vi’, vj’). {Comment: Substitute for ei found}

In Step 2­(1), we update Q by including the edges of Ei \R as a candidate of cut­set edges


for ei and subsequent tree edges. Specifically, in Step 2­(1)­(c) edge (vi , vj) is included in
Q if this is an edge from vi to vj with j>i. On the other hand, in [Step 2­(1)­(b)], edges
from ei to its descendants are deleted, since from now on these can no longer be a
cut­set edge. If we have an edge coming into vi from a previously found vertex vj , the
direction is reversed [Step 2­(1)­(a)]. In Step 2­(2) we look for a substitute ẽi of ei
included in Q. If we have an edge with the weight identical to w(ei) and emerging from a
vertex within the interval [σ1i , σ2i] [Step 2­(2)­(c)], this is a substitute for ei , and thus we
are done. If this is an edge from the above interval to the same interval, we delete this
edge from Q, and repeat Step 2­(2) again.

Example Consider the graph of Figure 4 with an MST T shown in thick lines. Nodes
and edges are numbered in the postorder fashion as traversed along T from node v10.
Table 3 shows w(ei), [σ1i , σ2i] and Q at each stage. The elements superscribed with ◦, ×
and ! show, respectively, the newly found, deleted and substitute for ei . The elements
associated with † shows that the edge direction is reversed here.

Figure 4.

Table 3. Behaviour of “Substitute” for the graph of Figure 4


Let All_MST2 be the algorithm obtained from All_MST1 by replacing Step 1 as follows.

Step 1 : Execute Substitute(F , R, T).

Computational complexity ofAll_MST2 can be evaluated as follows. First, note that Q


includes at most m elements, and for each non­tree edges at most two Inserts and two
Deletes are executed. For each tree edge at most one Find is executed. Since Q is an
ordered set, each of Insert, Delete and Find can be done in O(log m) time, provided that
Q is organized as an appropriate binary tree (such as the Adelson­Velskii and Landis
tree (AVL­tree) ). Thus, in total Substitutes can be done in O(m log m) = O(m log n)
time. All other computations, such as traversing G along T , renumbering V in postorder
fashion and finding intervals [σ1i , σ2i], can be accomplished in O(m) time. Thus, we have
the following.

The running time of All_MST2 is O(Nm log n).


References
1. T. Yamada, S. Kataoka and K. Watanabe, Listing all the minimum spanning trees in an
undirected graph, Published : International Journal of Computer Mathematics Vol. 87, No. 14,
November 2010, 3175–3185

2. Wikipedia :-
https://en.wikipedia.org/wiki/Time_complexity and
https://en.wikipedia.org/wiki/Big_O_notation

3. Graph Theory by Keijo Ruohonen, translated by Janne Tamminen, Kung-Chung Lee and
Robert Piché

You might also like