Part2 3GraphTraversal
Part2 3GraphTraversal
Discrete Mathematics
PART 2
GRAPH THEORY
(Lý thuyết đồ thị) 2
Content of Part 2
Chapter 1. Fundamental concepts
Chapter 2. Graph representation
Chapter 3. Graph Traversal
Chapter 4. Tree and Spanning tree
Chapter 5. Shortest path problem
Chapter 6. Maximum flow problem
Chapter 3
Graph traversal
5
Breadth-first Search (BFS)
(Tìm kiếm theo chiều rộng)
Breadth First Search
• Given
– a graph G=(V,E) – set of vertices and edges
– a distinguished source vertex s
• Breadth first search systematically explores the edges of G to discover every
vertex that is reachable from s.
• It also produces a ‘breadth first tree’ with root s that contains all the vertices
reachable from s.
• For any vertex v reachable from s, the path in the breadth first tree
corresponds to the shortest path in graph G from s to v.
• It works on both directed and undirected graphs.
7
Breadth First Search
• Given
– a graph G=(V,E) – set of vertices and edges
– a distinguished source vertex s
• Breadth first search systematically explores the edges of G to discover
every vertex that is reachable from s.
• For any vertex v reachable from s, the path in the breadth first tree
corresponds to the shortest path in graph G from s to v.
Adjacency list of s
s • From s: can go to b and e. Visit them and insert them into queue: Q = {b, e}
• Dequeue (Q): remove b out of Q, then Q = {e}
b e – From b: can go to a, c, k, s. But s was visited, so we visit only a, c, k;
and insert them into queue: Q = {e, a, c, k}
• Dequeue(Q): remove e out of Q, then Q = {a, c, k}
a c k – From e: can go to k, s. But all of them were visited.
• Dequeue(Q): remove a out of Q, then Q = {c, k}
d g •
– From a: can go to b, c. But these vertices were all visited.
Dequeue(Q): remove c out of Q, then Q = {k}.
– From c: can go to a, b, d, g, k. But a, b, k were visited, so we visit only
BFS(s) tree d, g; and insert them into queue: Q = {k, d, g}
• Dequeue(Q): remove k out of Q, then Q = {d, g}.
– From k: can go to b, c, e. But these vertices were all visited.
BFS creates a BFS tree • Dequeue (Q): remove d from Q, then Q = {g}
containing s as the root – From d: can go to c, g. But these vertices were all visited.
and all vertices that is • Dequeue(Q): remove g from Q, then Q = empty
reachable from s – From g: can go to d, c. But these vertices were all visited.
• Q is now empty. All vertices of the graph were visited. Algorithm is finished
Breadth-first Search
BFS(s)
// Breadth first search starts from vertex s
visited[s] 1; //visited
Q ; enqueue(Q,s); // insert s into Q
while (Q )
{
u dequeue(Q); // Remove u from Q
for v Adj[u]
if (visited[v] == 0) //not visited yet
{
visited[v] 1; //visited
enqueue(Q,v) // insert v into Q
}
}
(*Main Program*)
main ()
for s V // Initialize
s
visited[s] 0; b e
for s V
if (visited[s]==0) BFS(s); a c k
d g
Breadth-first Search
BFS(s)
// Breadth first search starts from vertex s
visited[s] 1; //visited
Q ; enqueue(Q,s); // insert s into Q
while (Q )
{
u dequeue(Q); // Remove u from Q
for v Adj[u]
if (visited[v] == 0) //not visited yet
{
visited[v] 1; //visited
enqueue(Q,v) // insert v into Q
}
}
(*Main Program*)
main ()
for s V // Initialize
visited[s] 0;
for s V
if (visited[s]==0) BFS(s);
Computation time of BFS
BFS(s) • Initialize: need O(|V|).
// Breadth first search starts from vertex s • The loop for
visited[s] 1; //visited
Q ; enqueue(Q,s); // insert s into Q – Each vertex is inserted into and
while (Q ) removed from queue exactly
{
u dequeue(Q); // Remove u from Q once, each operation needs
for v Adj[u]
if (visited[v] == 0) //not visited yet
O(1). So, the total computation
{ time with queue is O(|V|).
visited[v] 1; //visited
enqueue(Q,v) // insert v into Q – The adjacency list of each
} vertex is traversed exactly once.
}
The total length of all
(*Main Program*) adjacency list is O(|E|).
main ()
for s V // Initialize • In total, the computation time of
visited[s] 0; BFS(s) is O(|V|+|E|), linear to the
for s V size of adjacency list that represents
if (visited[s]==0) BFS(s);
the graph.
Breadth-first Search
• Input: Graph G = (V, E), either undirected or directed graph.
vertex s V: source vertex
• Output:
– d[v] = distance (length of shortest path) from s to v, where v V.
d[v] = if v is not reachable from s.
– pred[v] = u the vertex that is preceding v in the path from s to v
with length of d[v].
– Build BFS tree consisting of root s and all vertices that are
reachable from s.
Breadth-first Search
BFS(s)
//Breadth first search starts from vertex s
visited[s] 1; //visited
d[s] 0; pred[s] NULL;
Q ; enqueue(Q,s); //Insert s into Q
while (Q )
{
u dequeue(Q); //Remove u from Q
for v Adj[u] Q: queue contain all visited vertices
if (visited[v] == 0) //not visited yet visited[v]: mark visit state of
{ vertex v
visited[v] 1; //visited d[v]: distance from to v
d[v] d[u] + 1; pred[v] u;
pred[v]: vertex that is preceding v
enqueue(Q,v) //Insert v into Q
}
}
(*Main Program*)
for s V //initialize
{
visited[s] 0; d[s] ; pred[s] NULL;
}
for s V
if (visited[s]==0) BFS(s);
BFS
• Sequence of vertices by performing BFS (A):
A L0
A
B C D L1
B C D
E F L2
E F
Depth-first Search (DFS)
(Tìm kiếm theo chiều sâu)
Depth First Search ( DFS)
• It searches ‘deeper’ the graph when possible.
• Starts at the selected node and explores as far as possible along
each branch before backtracking.
(* Main Program*) DFS(s)
1. for s V 1. visited[s] true // Visist s
2. visited[s] false 2. for each v Adj[s]
3. for s V 3. if (visited[v] == false)
4. if (visited[s] == false) 4. DFS(v)
5. DFS(s)
DFS(a)
16
Computation time of DFS
(* Main Program*)
1. for s V DFS(s)
2. visited[s] false 1. visited[s] true // Visit s
3 for s V 2. for each v Adj[s]
4. if (visited[s] == false) 3. if (visited[v] == false)
5. DFS(s) 4. DFS(v)
• In main: the loops for on lines 1-2 and 3-5 require O(|V|), excluding computation
time of statement DFS(s).
• In DFS(s): the loop for on line 2 performs to traverse edges of graph:
– Lines 3-4 of DFS(s) perform |Adj[s]| times
– Each edge is traversed exactly once if graph is directed, otherwise exactly twice
if graph is undirected
The total computation time of DFS(s)in the main program is sV|Adj[s]| = O(|E|)
• Thus, computation time of DFS is O(|V|+|E|).
• So, DFS and BFS have the same computation time
DFS: If we want to show the path from vertex s to all other vertices of graph
Source vertex
a e g
b f
c d h
source
vertex
d[v] f[v] e g
a 1 | | |
b f
| |
| | |
c d h
Example: DFS
source
vertex
a e g
1 | | |
b f
2 | |
| | |
c d h
Example: DFS
source
vertex
a e g
1 | | |
b f
2 | |
3 | | |
c d h
Example: DFS
source
vertex
a e g
1 | | |
b f
2 | |
3 | 4 | |
c d h
Example: DFS
source
vertex
a e g
1 | | |
b f
2 | |
3 | 4 5 | |
c d h
Example: DFS
source
vertex
a e g
1 | | |
b f
2 | |
3 | 4 5 | 6 |
c d h
Example: DFS
source
vertex
a e g
1 | | |
b f
2 | 7 |
3 | 4 5 | 6 |
c d h
Example: DFS
source
vertex
a e g
1 | 8 | |
b f
2 | 7 |
3 | 4 5 | 6 |
c d h
Example: DFS
source
vertex
a e g
1 | 8 | |
b f
2 | 7 9 |
3 | 4 5 | 6 |
c d h
Example: DFS
source
vertex
a e g
1 | 8 | |
b f
2 | 7 9 |10
3 | 4 5 | 6 |
c d h
Example: DFS
source
vertex
a e g
1 | 8 |11 |
b f
2 | 7 9 |10
3 | 4 5 | 6 |
d h
Example: DFS
source
vertex
a e g
1 |12 8 |11 |
b f
2 | 7 9 |10
3 | 4 5 | 6 |
c d h
Example: DFS
source
vertex
a e g
1 |12 8 |11 13|
b f
2 | 7 9 |10
3 | 4 5 | 6 |
c d h
Example: DFS
source
vertex
a e g
1 |12 8 |11 13|
b f
2 | 7 9 |10
3 | 4 5 | 6 14|
c d h
Example: DFS
source
vertex
a e g
1 |12 8 |11 13|
b f
2 | 7 9 |10
3 | 4 5 | 6 14|15
c d h
Example: DFS
source
vertex
a e g
1 |12 8 |11 13|16
bb f
2 | 7 9 |10
3 | 4 5 | 6 14|15
c d h
Lemma of nested intervals
Given directed graph G = (V, E), and arbitrary DFS tree, 2 arbitrary vertices u, v of G. Then
– u is a descendant of v iff [d[u], f[u]] [d[v], f[v]]
– u is ancestor of v iff [d[u], f[u]] [d[v], f[v]]
– u and v are not related iff [d[u], f[u]] and [d[v], f[v]] are not intersecting.
Lemma of nested intervals
Given directed graph G = (V, E), and arbitrary DFS tree, 2 arbitrary vertices u, v of G. Then
– u is a descendant of v iff [d[u], f[u]] [d[v], f[v]]
– u is ancestor of v iff [d[u], f[u]] [d[v], f[v]]
– u and v are not related iff [d[u], f[u]] and [d[v], f[v]] are not intersecting.
DFS: Edges classification
• DFS creates a classification of the edges of given graph:
– Tree edge (cạnh cây): the edge whereby from a vertex visits a new vertex
(cạnh theo đó từ một đỉnh đến thăm đỉnh mới)
– Back edge (cạnh ngược): going from descendants to ancestors (đi từ con
cháu đến tổ tiên)
– Forward edge (cạnh tới): going from ancestor to descendant (đi từ tổ tiên
đến con cháu)
– Cross edge (cạnh vòng): edge connecting 2 non-related vertices (giữa hai
đỉnh không có họ hàng)
• Note: there are many applications using tree edges and back edges
Example
Given graph G as shown in the figure below
Question 1: Represent G by using
1. Adjacency matrix
2. Weight matrix 3 3
3. Adjacency list 9
Question 2: Given source vertex S 13
23
Draw trees BFS(S) and DFS(S) 7
2
6
11
1
Some applications of DFS
1. Connectedness of graph
2. Find the path from s to t
3. Cycle detection
4. Check strongly connectedness
5. Graph orientation
6. Topo order
The problem of connectivity
• Problem: Given undirected graph G = (V,E). How many
connected components are there in this graph, and each
connected component consists of which vertices?
• Answer: Use DFS (BFS) :
– Each time the function DFS (BFS) is called in the main program,
there is one more connected component found in the graph
DFS to solve the problem of connectivity
(* Main Program*) DFS(s)
1. for s V 1. visited[s] true // Visist s
2. visited[s] false 2. for each v Adj[s]
3. for s V 3. if (visited[v] == false)
4. if (visited[s] == false) 4. DFS(v)
5. DFS(s)
(* Main Program*)
1. for u V DFS(u)
2. id[u] 0; 1. id[u] cnt;
3. cnt 0; //cnt – number of 2. for each v Adj[u]
connected components 3. if (id[v] == 0)
4. for u V 4. DFS(v);
5. if (id[u] == 0){
6. cnt cnt +1;
7. DFS(u) ;
8. }
BFS(s)
BFS to solve the problem of connectivity 1. id[s] cnt
2. Q ; enqueue(Q,s); //insert s into Q
3. while (Q )
4. {
5. u dequeue(Q); //Remove u from Q
6. for v Adj[u]
7. if (id[v] == 0) //v not visited yet
8. {
9. id[v] cnt;
10. enqueue(Q,v) //insert v into Q
11. }
12. }
(* Main Program*)
1. for s V
2. id[s] 0
3. cnt 0 //cnt – number of connected components
4. for s V
5. if (id[s] == 0){
6. cnt cnt +1
7. BFS(s)
8. }
Example
Using the DFS algorithm determine the number of connected components of the
following graph, and show which vertices each connected component consists of
a e g
b f i
c d h
DFS(u)
1. visited[u] true //visit u
2. for each v Adj[u]
3. if (visited[v] == false)
4. DFS(v)
DFS and cycle detection: Method 2
• How to modify so we can detect the back edge the cycle
DFS(u)
1. visited[u] 1 //visit u
2. for each v Adj[u]
(* Main Program*) 3. if (visited[v] == 1)
1. for u V 4. {
2. visited[u] 0 5. print (“Graph has cycle”);
3. for u V 6. exit();
4. if (visited[u] == 0) 7. }
5. DFS(u) 8. else if(visited[v]==0) DFS(v)
9. visited[u] 2 //u is at state of finish traversal
DFS and cycle detection
• Question: What is the computation time?
Answer: It is the computation time of DFS: O(|V|+|E|).
• Question: If G is undirected graph, can we evaluate the computation
time more precisely?
Answer: Computation time is O(|V|), because:
– In the forest (graph does not contain cycle): |E| |V| - 1
– Thus, if graph consists of |V| edges, then it for sure contain the
cycle, and algorithm finishes.
a d a d
f c f
c
b e b e
Graph G Graph GT
Algorithm to check strongly connectedness of directed graph
64
Some applications of DFS
1. Connectedness of graph
2. Find the path from s to t
3. Cycle detection
4. Check strongly connectedness
5. Graph orientation
6. Topo order
Graph orientation (Định hướng đồ thị)
• Problem: Given undirected connected graph G= (V, E). Find the way
to orient its edges such that the obtained directed graph is strongly
connected or answer that G is non-directional (G là không định hướng
được).
• Orientation algorithm : During the execution of DFS(G), we
orient: (1) tree edges of DFS direct from the ancestor to the
descendant, (2) back edges of DFS direct from descendant to ancestor.
Denote the obtained graph by G()
• Lemma. G is directional if and only if G() is strongly connected.
Example: Graph orientation
Graph G a d a d
f c f
c
b e b e
Graph G()
DFS(a) a
b
c e
Step 2: Applying DFS to check whether G() is strongly
d connected
f
Some applications of DFS
1. Connectedness of graph
2. Find the path from s to t
3. Cycle detection
4. Check strongly connectedness
5. Graph orientation
6. Topological order
6.Topological order (Sắp xếp topo)
A typical application of topological order is to plan a sequence of jobs:
• Each vertex of the graph represents one job to be performed.
• The jobs are interdependent. So some jobs cannot be done before
others are completed.
Example:
• IT3302 (C basic) is a prerequisite course when registering IT3312 (C
advanced)
IT3302 IT3312
70
6.Topological order (Sắp xếp topo)
• Problem: Given directed acyclic graph G= (V, E). Find the way to
order vertices of G such that if there is a directed edge (u,v) in G, then
u is always previous v in this order (in other words, find the way to
index vertices such that edges of graph is always directed from vertex
with smaller index to vertex with larger index).
Example: B 2 4
1 C E
3 A D 5
2 methods:
• DFS algorithm
• BFS with modification
71
Example: Renovating office for rent
B I
C
J
E F
A D
G H 72
(1) Apply DFS
The algorithm can be briefly described as follows:
• Performing DFS (G), when each vertex is visited finish, we
put it at the top of the linked list (which means that the later
the vertices that finish visit will be closer to the top of the
list).
• When DFS(G) terminates, the obtained linked list gives us
the order of tasks to be executed.
73
Topological sorting algorithm: apply DFS
(* Main Program*) DFS(s)
1. for s V 1. visited[s] true // Visist s
2. visited[s] false 2. for each v Adj[s]
3. for s V 3. if (visited[v] == false)
4. if (visited[s] == false) 4. DFS(v)
5. DFS(s)
TopoSort(G)
1. for sV visited[s] = false; // initialize
2. L = new(linked_list); // initialize the empty linked list L
3. for sV
4. if (visited[s] == false) DFS(s);
5. return L; // L gives the order
DFS (s) { // starting searching from s
1. visited[s] = true; // mark s as visited
2. for vAdj(s)
3. if (visited[v] == FALSE) DFS(v);
4. Insert s at the beginning of list L // s is visited finish
} 74
Computation time of TopoSort(G) is O(|V|+|E|).
Example 1: Topological order by using DFS
Graph G
75
Example 1: Topological order by using DFS
10 / 19
1 / 20
11 / 16 17/18 DFS(G)
12 / 15
Topological order
13 / 14
2 /9
3/ 4 5/ 8 6/ 7 Linked list L:
a f j e g h i d c b
Example 2: Topological order by using DFS
77
(2) BFS with modification
Another algorithm for topological sorting is based on the
following clause:
78
Topological order: BFS with modification
From the proposition, we have the algorithm:
• First, find vertices with in-order degree of zero. Obviously,
we can number them in an arbitrary order starting with 1.
• Next, delete all vertices that are numbered from the graph
and all edges going out of them, we then obtain a new graph
with no cycles. And the process is repeated with this new
graph.
• That process will be continued until all vertices of the graph
are numbered.
79
Topological order: BFS with modification
for v V do
Calculate InDegree[v] – indegree of vertex v;
Q = queue contains all vertices of indegree = 0;
num=0;
while Q do
v = dequeue(Q); num=num+1;
Number vertex v by num;
for u Adj(v) do
InDegree[u]=InDegree[u] -1;
if InDegree[u]==0
Enqueue(Q,u);
Computation time: (|V|+|E|)
80
Topological order: BFS with modification
9 6 3
4 5
0 1 2 7 8
Q={0, 9}
Output:
81
Topological order: BFS with modification
9 6 3
-1
4 5
-1
0 1 2 7 8 -1
1
Dequeue 0; Q={9}
Output: 0
82
Topological order: BFS with modification
9 6 3
-1
4 5
-1
0 1 2 7 8 -1
1
Dequeue 0; Q={9}
Q={9, 1}
Output: 0
83
Topological order: BFS with modification
2
9 6 3
4 5
0 1 2 7 8 -1
1
Dequeue 9; Q={1}
Output: 0 9
84
Topological order: BFS with modification
2
9 6 3
4 5
0 1 2 7 8 -1
1
Dequeue 9; Q={1}
Q={1,6}
Output: 0 9
85
Topological order: BFS with modification
2
9 6 3
-1
4 5
0 1 2 7 8
1 3
Dequeue 1; Q={6}
Output: 0 9 1
86
Topological order: BFS with modification
2 4
9 6 3
-1
4 5 -1
0 1 2 7 8
1 3
Dequeue 6; Q={}
Output: 0 9 1 6
87
Topological order: BFS with modification
2 4
9 6 3
-1
4 5 -1
0 1 2 7 8
1 3
Dequeue 6; Q={}
Q={3,2}
Output: 0 9 1 6
88
Topological order: BFS with modification
2 4 5
9 6 3
4 5
-1
0 1 2 7 8
1 3 -1
Dequeue 3; Q={2}
Output: 0 9 1 6 3
89
Topological order: BFS with modification
2 4 5
9 6 3
4 5
-1
0 1 2 7 8
1 3 -1
Dequeue 3; Q={2}
Q={2, 4}
Output: 0 9 1 6 3
90
Topological order: BFS with modification
2 4 5
9 6 3
4 5
0 1 2 7 8 -1
1 3 6
-1
Dequeue 2; Q={4}
Output: 0 9 1 6 3 2
91
Topological order: BFS with modification
2 4 5
9 6 3
4 5
0 1 2 7 8 -1
1 3 6
-1
Dequeue 2; Q={4,
Q={4} 7}
Output: 0 9 1 6 3 2
92
Topological order: BFS with modification
2 4 5
9 6 3
7
4 5
-1
0 1 2 7 8
1 3 6
Dequeue 4; Q={7}
Output: 0 9 1 6 3 2 4
93
Topological order: BFS with modification
2 4 5
9 6 3
7
4 5
-1
0 1 2 7 8
1 3 6
Dequeue 4; Q={7,
Q={7} 5}
Output: 0 9 1 6 3 2 4
94
Topological order: BFS with modification
2 4 5
9 6 3
7
4 5
0 1 2 7 8
1 3 6 8
Dequeue 7; Q={5} -1
Output: 0 9 1 6 3 2 4 7
95
Topological order: BFS with modification
2 4 5
9 6 3
7
4 5
0 1 2 7 8
1 3 6 8
Dequeue 7; Q={5}
Q={5,8} -1
Output: 0 9 1 6 3 2 4 7
96
Topological order: BFS with modification
2 4 5
9 6 3
7 9
4 5
0 1 2 7 8
1 3 6 8
Dequeue 5; Q={8}
Output: 0 9 1 6 3 2 4 7 5
97
Topological order: BFS with modification
2 4 5
9 6 3
7 9
4 5
0 1 2 7 8
1 3 6 8 10
Dequeue 8; Q={}
Output: 0 9 1 6 3 2 4 7 5 8
98
Topological order: BFS with modification
2 4 5
9 6 3
7 9
4 5
0 1 2 7 8
1 3 6 8 10
Output: 0 9 1 6 3 2 4 7 5 8
99