Improvements for graph algorithms
This commit is contained in:
parent
086d0e61cd
commit
31ff123f33
|
@ -133,17 +133,17 @@ vector<int> 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<int> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<pair<int,int>> 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});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in New Issue