From 31ff123f33d317c5a27c9cc21a7cdaa8f06ab348 Mon Sep 17 00:00:00 2001 From: Antti H S Laaksonen Date: Mon, 17 Apr 2017 13:58:04 +0300 Subject: [PATCH] Improvements for graph algorithms --- chapter12.tex | 47 ++++++++++++++++++++++++----------------------- chapter13.tex | 45 +++++++++++++++++++++++---------------------- chapter14.tex | 6 +++--- chapter15.tex | 16 ++++++++-------- 4 files changed, 58 insertions(+), 56 deletions(-) diff --git a/chapter12.tex b/chapter12.tex index ae8be4e..3fb776a 100644 --- a/chapter12.tex +++ b/chapter12.tex @@ -133,17 +133,17 @@ vector v[N]; \end{lstlisting} and also maintains an array \begin{lstlisting} -bool z[N]; +bool visited[N]; \end{lstlisting} that keeps track of the visited nodes. -Initially, each array value is 0, +Initially, each array value is \texttt{false}, and when the search arrives at node $s$, -the value of \texttt{z}[$s$] becomes 1. +the value of \texttt{visited}[$s$] becomes \texttt{true}. The function can be implemented as follows: \begin{lstlisting} void dfs(int s) { - if (z[s]) return; - z[s] = 1; + if (visited[s]) return; + visited[s] = true; // process node s for (auto u: v[s]) { dfs(u); @@ -308,38 +308,39 @@ a queue that contains nodes. At each step, the next node in the queue will be processed. -The following code begins a breadth-first -search at node $x$. -The code assumes that the graph is stored -as adjacency lists and maintains a queue +The following code assumes that the graph is stored +as adjacency lists and maintains the following +data structures: \begin{lstlisting} queue q; +bool visited[N]; +int distance[N]; \end{lstlisting} -that contains the nodes in increasing order + +The queue \texttt{q} +contains the nodes in increasing order of their distance. New nodes are always added to the end of the queue, and the node at the beginning of the queue is the next node to be processed. - -In addition, the code uses arrays -\begin{lstlisting} -bool z[N]; -int e[N]; -\end{lstlisting} -so that the array \texttt{z} indicates -which nodes the search has already visited -and the array \texttt{e} will contain the +The array \texttt{visited} indicates +which nodes the search has already visited, +and the array \texttt{distance} will contain the distances to all nodes in the graph. -The search can be implemented as follows: + +The search can be implemented as follows, +starting at node $x$: \begin{lstlisting} -z[x] = 1; e[x] = 0; +visited[x] = true; +distance[x] = 0; q.push(x); while (!q.empty()) { int s = q.front(); q.pop(); // process node s for (auto u : v[s]) { - if (z[u]) continue; - z[u] = 1; e[u] = e[s]+1; + if (visited[u]) continue; + visited[u] = true; + distance[u] = distance[s]+1; q.push(u); } } diff --git a/chapter13.tex b/chapter13.tex index 5143d06..8b5c1fd 100644 --- a/chapter13.tex +++ b/chapter13.tex @@ -204,18 +204,19 @@ The algorithm consists of $n-1$ rounds, and on each round the algorithm goes through all edges of the graph and tries to reduce the distances. -The algorithm constructs an array \texttt{e} +The algorithm constructs an array \texttt{distance} that will contain the distance from $x$ to all nodes in the graph. The initial value $10^9$ means infinity. \begin{lstlisting} -for (int i = 1; i <= n; i++) e[i] = 1e9; -e[x] = 0; +for (int i = 1; i <= n; i++) distance[i] = 1e9; +distance[x] = 0; for (int i = 1; i <= n-1; i++) { for (int a = 1; a <= n; a++) { for (auto b : v[a]) { - e[b.first] = min(e[b.first],e[a]+b.second); + distance[b.first] = min(distance[b.first], + distance[a]+b.second); } } } @@ -234,7 +235,7 @@ Thus, a possible way to make the algorithm more efficient is to stop the algorithm if no distance can be reduced during a round. -\subsubsection{Negative cycle} +\subsubsection{Negative cycles} \index{negative cycle} @@ -300,22 +301,22 @@ node $b$ is added to the queue. The following implementation uses a \texttt{queue} \texttt{q}. -In addition, an array \texttt{z} indicates +In addition, an array \texttt{inqueue} indicates if a node is already in the queue, in which case the algorithm does not add the node to the queue again. \begin{lstlisting} -for (int i = 1; i <= n; i++) e[i] = 1e9; -e[x] = 0; +for (int i = 1; i <= n; i++) distance[i] = 1e9; +distance[x] = 0; q.push(x); while (!q.empty()) { int a = q.front(); q.pop(); - z[a] = 0; + inqueue[a] = false; for (auto b : v[a]) { - if (e[a]+b.second < e[b.first]) { - e[b.first] = e[a]+b.second; - if (!z[b]) {q.push(b); z[b] = 1;} + if (distance[a]+b.second < distance[b.first]) { + distance[b.first] = distance[a]+b.second; + if (!inqueue[b]) {q.push(b); inqueue[b] = true;} } } } @@ -562,28 +563,28 @@ priority_queue> q; A small difficulty is that in Dijkstra's algorithm, we should find the node with the \emph{minimum} distance, while the C++ priority queue finds the \emph{maximum} -element as default. +element by default. An easy trick is to use \emph{negative} distances, which allows us to directly use the C++ priority queue. The code keeps track of processed nodes -in an array \texttt{z}, -and maintains the distances in an array \texttt{e}. +in an array \texttt{ready}, +and maintains the distances in an array \texttt{distance}. Initially, the distance to the starting node is 0, and the distance to all other nodes is $10^9$ (infinite). \begin{lstlisting} -for (int i = 1; i <= n; i++) e[i] = 1e9; -e[x] = 0; +for (int i = 1; i <= n; i++) distance[i] = 1e9; +distance[x] = 0; q.push({0,x}); while (!q.empty()) { int a = q.top().second; q.pop(); - if (z[a]) continue; - z[a] = 1; + if (ready[a]) continue; + ready[a] = true; for (auto b : v[a]) { - if (e[a]+b.second < e[b.first]) { - e[b.first] = e[a]+b.second; - q.push({-e[b.first],b.first}); + if (distance[a]+b.second < distance[b.first]) { + distance[b.first] = distance[a]+b.second; + q.push({-distance[b.first],b.first}); } } } diff --git a/chapter14.tex b/chapter14.tex index cdccf57..49fb16b 100644 --- a/chapter14.tex +++ b/chapter14.tex @@ -136,7 +136,7 @@ or the length of the longest path from the node to a leaf. As an example, let us calculate for each node $s$ -a value $\texttt{c}[s]$: the number of nodes in its subtree. +a value $\texttt{count}[s]$: the number of nodes in its subtree. The subtree contains the node itself and all nodes in the subtrees of its children. Thus, we can calculate the number of nodes @@ -144,11 +144,11 @@ recursively using the following code: \begin{lstlisting} void dfs(int s, int e) { - c[s] = 1; + count[s] = 1; for (auto u : v[s]) { if (u == e) continue; dfs(u, s); - c[s] += c[u]; + count[s] += count[u]; } } \end{lstlisting} diff --git a/chapter15.tex b/chapter15.tex index 57fb917..afcb0f6 100644 --- a/chapter15.tex +++ b/chapter15.tex @@ -504,17 +504,17 @@ efficiently by following the corresponding chain. The union-find structure can be implemented using arrays. In the following implementation, -the array \texttt{k} contains for each element +the array \texttt{link} contains for each element the next element in the chain or the element itself if it is a representative, -and the array \texttt{s} indicates for each representative +and the array \texttt{size} indicates for each representative the size of the corresponding set. Initially, each element belongs to a separate set: \begin{lstlisting} -for (int i = 1; i <= n; i++) k[i] = i; -for (int i = 1; i <= n; i++) s[i] = 1; +for (int i = 1; i <= n; i++) link[i] = i; +for (int i = 1; i <= n; i++) size[i] = 1; \end{lstlisting} The function \texttt{find} returns @@ -524,7 +524,7 @@ the chain that begins at $x$. \begin{lstlisting} int find(int x) { - while (x != k[x]) x = k[x]; + while (x != link[x]) x = link[x]; return x; } \end{lstlisting} @@ -552,9 +552,9 @@ set to the larger set. void unite(int a, int b) { a = find(a); b = find(b); - if (s[a] < s[b]) swap(a,b); - s[a] += s[b]; - k[b] = a; + if (size[a] < size[b]) swap(a,b); + size[a] += size[b]; + link[b] = a; } \end{lstlisting} \end{samepage}