\documentclass[11pt]{article}

\usepackage{fullpage}
\usepackage{graphicx,epsfig,color,amssymb}


\begin{document}

\title{{\bf Traversing a graph: BFS and DFS}\\
\normalsize{(CLRS 22.2, 22.3)}}


\date{}

\maketitle

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The most fundamental graph problem is traversing the graph.

\begin{itemize}
\item There are two standard (and simple) ways of traversing all
vertices/edges in a graph in a systematic way: BFS and DFS. 
\item Most fundamental algorithms on graphs (e.g finding cycles,
  connected components) are applications of graph traversal.
\item Like finding the way out of a maze (maze = graph). Need to be careful to not
  get stuck in the graph, so we need to mark vertices that we've
  encountered; and we need to make sure we don't skip anything.
\item Basic idea: over the course of the traversal a vertex progresses
  from undiscovered, to  discovered, to completely-discovered: 

\begin{itemize} 
\item undiscovered: initially (WHITE)
\item discovered:  after it's encountered, but before it's completely
  explored (GRAY)
\item completely explored: the vertex after we visited all its
  incident edges (BLACK)
\end{itemize} 

\item We start with a single vertex and evaluate its outgoing edges: 
\begin{itemize} 
\item   If an edge goes to an undiscoverd vertex, we mark it as discovered
  and add it to the list of discovered vertices.  
\item If an edge goes to a completely explored vertex, we ignore it
  (we've already been there)
\item If an edge goes to an already discovered  vertex, we ignore it (it's on the list). 
\end{itemize}
\item Analysis: Each edge is visited once (for directed graphs), or
  twice (undirected graphs --- once when exploring each
  endpoint) $\Rightarrow O(|V| + |E|)$
\item Depending on how we store the list of discovered vertices we get
  BFS or DFS:
  \begin{itemize} 
  \item queue: explore oldest vertex first. The exploration propagates
    in layers form the starting vertex.
  \item stack: explore newest vertex first. The exploration goes along
    a path, and backs up only when new unexplored vertices are not
    available.
  \end{itemize} 

\end{itemize}

\section*{Breadth-first search (BFS)}
\begin{itemize}
\item We use a queue $Q$ to hold all gray vertices---vertices we have
  seen but are still not done with.

\item We remember from which vertex a given vertex $v$ is colored gray
  -- i.e. the node that discovered $v$ first; this is called
  parent[$v$].

\item  We also maintain $d[v]$, the length of the path from $s$ to
  $v$.  Initially $d[s]=0$. 

  \fbox{
\parbox{10cm}{
{\sc BFS($s$) }
\begin{itemize}
\item[] color[$s$] = gray
\item[] $d[s] = 0$
\item[] ENQUEUE($Q,s$)
\item[] WHILE $Q$ not empty DO
        \begin{itemize}
        \item[] DEQUEUE($Q,u$)
        \item[] FOR each $v \in adj[u]$ DO
                \begin{itemize}
                \item[] IF color[$v$] = white THEN
                        \item[] ~~~~color[$v$] = gray
                        \item[] ~~~~$d[v] = d[u] + 1$
                        \item[] ~~~~parent[$v$] = u   \textcolor{blue}{//(u,v) is a tree-edge}
                        \item[] ~~~~ENQUEUE($Q,v$)
        %        \item[] FI
                        \item [] \textcolor{blue}{//ELSE v  is not white, (u,v) is
                          non-tree edge}
                \item[] color[$u$] = black
                \end{itemize}
        \end{itemize}
%\item[] OD
\end{itemize}
}}
\vspace*{\baselineskip}

%%\item Analysis: Algorithm runs in $O(\vert V \vert + \vert E \vert)$ time


\item Example (for directed graph): \\
\centerline{\includegraphics[width=5cm]{bfs1.png} \hspace{1cm}
\includegraphics[width=5cm]{bfs2.png}
}

\item If graph is not connected we start the traversal
at all nodes until the entire graph is explored. \\

\fbox{
\parbox{8cm}{ 
BFS(G)\\
\begin{itemize}
\item [] FOR each vertex $u \in V $ DO
  \begin{itemize}
  \item[] IF color[$u$] = white THEN BFS($u$)
  \end{itemize}
  \end{itemize}
%OD
}}
\end{itemize}

\newpage
{\bf Properties of BFS} 


\begin{itemize}


\item During BFS(v) each edge in G is classified as:
\begin{itemize} 
  \item tree edge: an edge leading to an unmarked vertex 
  \item non-tree edge: an edge leading to a marked
    vertex.
\end{itemize} 


\item Each vertex, except the source vertex $s$, has a parent;  these
  edges $(v, parent[v])$ define a tree, called the  {\em BFS-tree}.


\item {\bf Lemma: }   On  a directed graph, BFS(s) reaches all vertices reachable from
  $s$. 
On an undirected graph, BFS(s) visits all vertices in the connected component (CC) of $s$, and
the BFS-tree obtained is a spanning tree of $CC(s)$. 

\textcolor{blue} { Proof sketch: Assume by contradiction that there is a
  vertex $v$ in CC(u) that is not reached by BFS(u). Since $u,v$ are
  in same CC, there must exist a path $v_0=u, v_1, v_2, ..., v_k, v$
  connecting $u$ to $v$. Let $v_i$ be the last vertex on this path
  that is reached by BFS(u) ($v_i$ could be $u$). When exploring
  $v_i$, BFS must have explored edge $(v_i, v_{i+1})$,..., leading
  eventually to $v$. Contradiction.  }


\item {\bf Lemma:} BFS(s) runs in $O(|V_c| + |E_c|)$, where $V_c, E_c$
  are the number of vertices and edges in CC(s). When run on the
  entire graph, BFS(G) runs in $O(|V|+|E|)$ time. Put differently, BFS
  runs in linear time in the size of the graph.

  Proof: It explores every vertex once. Once a vertex is marked, it's
  not explored again.  It traverses each edge twice. Overall,
  $O(|V|+|E|)$.

\item {\bf Lemma:} Let $x$ be a vertex reached in BFS(s). Its distance
  $d[x]$ represents the the shortest path from $s$ to $x$ in $G$.

    \textcolor{blue}{Proof idea: All vertices $v$ which are one edge
    away from $s$ are discovered when exploring $s$ and are set with
    $d[v]=1$. Similarly all vertices that are one edge away from
    vertices at distance 1, are explored and their distance set to
    $d=2$. And so on.  }

\item {\bf Lemma:} For undirected graphs, for any non-tree edge $(x,y)$ in
  BFS($v$), the level of $x$ and $y$ differ by at most one.

  \textcolor{blue}{Proof idea: Observe that, at any point in time, the
    vertices in the queue have distances that differ by at most 1.
    Let's say $x$ comes out first from the queue; at this time $y$
    must be already marked (because otherwise $(x,y)$ would be a tree
    edge). Furthermore $y$ has to be in the queue, because, if it
    wasn't, it means it was already deleted from the queue and we
    assumed $x$ was first.  So $y$ has to be in the queue, and we have
    $|d(y)-d(x)| \le 1$ by above observation.  }
\end{itemize}









\newpage
\section*{Depth-first search (DFS)}
\begin{itemize}
\item Use stack instead of queue  to hold discovered vertices: 
        \begin{itemize}
        \item We go ``as deep as possible'', go back until we find
          first unexplored adjacent vertex
        \end{itemize}
\item Useful to compute ``start time'' and ``finish time'' of
vertex $u$
        \begin{itemize}
        \item {\em Start time\/} d[$u$]: time when a  vertex
        is first visited.
        \item {\em Finish time\/} f[$u$]: time when all
        adjacent vertices of $u$ have been visited.
        \end{itemize}
\item We can write DFS iteratively using the same algorithm as for BFS
but with a STACK instead of a QUEUE, or, we can write a recursive DFS
procedure
        % \begin{itemize}
        % \item We will color a vertex gray when we first meet it and black
        % when we finish processing all adjacent vertices.
        % \end{itemize}

\fbox{
\parbox{8cm}{
{\sc DFS($u$) } 
\begin{itemize}
\item[] color[$u$] = gray
\item[] $d[u]$ = time
\item[] time = time + 1
\item[] FOR each $v \in adj[u]$ DO
        \begin{itemize}
        \item[] IF color[$v$] = white THEN
                \begin{itemize}
                \item[] parent[$v$] = $u$
                \item[] {\sc DFS(v)}
                \end{itemize}
  %      \item[] FI
        \end{itemize}
%\item[] OD
\item[] color[$u$] = black
\item[] $f[u]$ = time
\item[] time = time + 1
\end{itemize}
}}


\item Example: \\
\centerline{
\includegraphics[width=5cm]{dfs1.png}
\hspace{1cm}
\includegraphics[width=5cm]{dfs2.png}
}

{\bf DFS Properties:} 
\item DFS(u) reaches all vertices reachable from $u$. On undirected
  graphs, DFS(u) visits all vertices in CC(u), and the DFS-tree
  obtained is a spanning tree of $G$. 

\item Analysis: DFS(s) runs in $O(|V_c| + |E_c|)$, where $V_c, E_c$
  are the number of vertices and edges in CC(s) (reachable from $s$,
  for directed graphs). When run on the entire graph, DFS(G) runs in
  $O(|V|+|E|)$ time. Put differently, DFS runs in linear time in the
  size of the graph.

\item As with BFS $(v, parent[v])$ forms a tree, the {\em DFS-tree}

\item Nesting of descendants: If $u$ is descendent of $v$ in DFS-tree
  then $d[v] < d[u] < f[u] < f[v]$.

\end{itemize}


\end{document}
