mik final
mik final
Submitted by :-
Atul Kumar
2015MAS7065
Thanks
Atul kumar
Mohd. Irshad Khan
Content
● Abstract
2. Time Complexity
● 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 cutset where we come to
the concepts of substitute, and it would become of O(Nmn). Finally we study the
improvement in the cutset 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
1. G is a tree.
2. There is a unique path between any two vertices in G.
3. G is connected but Ge is disconnected for every edge e of G.
4. G is connected and m = n1.
5. G is acyclic and m = n1.
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, Gxy is disconnected. Since,
xy is a arbitrary edge of G, Ge is disconnected for every edge e of G. Hence, G is connected but
Ge is disconnected for every edge e of G.
(3)⇒(4) : By assumption, G is connected. So we need only to show that m=n1 . We prove this
by induction . A connected graph with n=1 or n=2 vertices has n1 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 Ge is disconnected for every edge e of G. Let e=xy be
any edge of G. Now, Ge 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 n1 edges.
(4)⇒(5) : We have to show that every connected graph G with n vertices and n1 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 n1 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 n1
edges, since G is connected and has n1 edges, G has a vertex of degree 1. Let x be a vertex of
degree 1 in G. let G’ = Gx. Now, G’ is connected and has n1 vertices and n2 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’= Gx is acyclic, G must be acyclic. So, by induction,every connected graph with n vertices and
n1 edges are acyclic.
(5)⇒(6) : Suppose that G is acyclic and that m=n1. 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 = ∑(ni1) = nk. 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 :
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=mn+1. Define Gi , 0 ≤ i ≤ k, recursively, as follows:
Since, Gi has exactly n1+ki edges, Gi is cyclic for each i, 0 ≤ i ≤ k1 . So, each Gi , 0≤
i ≤ k1 , has a cycle. If Gi1 is connected, then Gi is also connected, as ei belongs to some
cycle of Gi1 , 0 ≤ i ≤ k1 . Hence, Gk is connected and has exactly n1 edges. So, Gk is a
tree . Let T = Gk , now T is a spanning tree of G.
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 = DA, where D is a diagonal matrix with Djj = deg(vj) and A is the graph’s
adjacency matrix.
(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 ).
Now, we will discuss two recursive algorithms viz depthfirst search and breadthfirst
search to find out a spanning tree of a connected, undirected and simple graph.
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
Code in C++
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
vector<int> v;
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;
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[x1][y1]=1;
a[y1][x1]=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;
}
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
Code in C++
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
vector<int> v;
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[x1][y1]=1;
a[y1][x1]=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(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
Definition : The cost of a spanning tree T= ( V ,E’ ) of a weighted graph G = ( V , E) with cost
matrix C is defined by
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 n1 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 nondecreasing 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 n1 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 n1 edges to T, then T become a spanning tree of G. Since
the edge are examined for inclusion in the nondecreasing order of costs, T turn out to be an
MST.
Kruskal’s Algorithm
//Kruskal's Algorithm
#include<iostream>
#include<vector>
#include<algorithm>
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[x1][y1]=w;
a[y1][x1]=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<n1;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 n1 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 n1 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∈VV’. 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
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 VV’.
Let e = xy be a least cost edge such that x∈V’ and
y∈VV’.
V’ = V’∪{y};
E’ = E’∪{e};
}
}
Code in C++
#include<iostream>
#include<vector>
using namespace std;
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[x1][y1]=w;
a[y1][x1]=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 worstcase 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 averagecase 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.
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 "bigoh"
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:
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.
Algorithm All_MST(F,R)
Figure 1
Due to the recursive nature of the algorithm, the subproblems are visited and numbered
in a depthfirst 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.
∗ ′
̂ = { T ∪ {e }\{d}
T
if d ∈ C0
T ∗ ∪ {c}\{d} if d ∈ C0
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.
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
Let Ei := {(vi , vj) ∈ E | (vi , vj) ∉ T} be a set of nontree 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 cutset edge at this, and subsequent, stage. We call Q the set of quasicuts,
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
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.
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é