Dijkstra: Difference between revisions
No edit summary |
|||
(14 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
{{#ev:youtube|https://www.youtube.com/watch?v=6nSc8ojXZ1A|500|right|Chapters | |||
#[00:00] Einführung | |||
#[05:33] Ändern sich die Pfade stark in jeder Iteration? | |||
#[06:08] Auf was für Strukturen arbeiten wir eigentlich? | |||
#[07:26] Distanzen und kürzeste Pfade | |||
#[10:59] Varianten des Kürzeste-Pfade-Problems | |||
#[14:00] Dijkstra implementiert | |||
#[16:00] Wieso funktioniert dieser Algorithmus, warum ist er korrekt? | |||
#[21:28] Was gibt es zum Preprocessing bzw. Induktionsanfang zu sagen? | |||
#[21:57] Was ist in der Queue? | |||
#[22:15] Was wissen wir über die erledigten Knoten? | |||
#[23:00] Und was wissen wir über die unerledigten Knoten? | |||
#[23:49] Und was ist mit der asymptotischen Komplexität? | |||
|frame}} | |||
[[Category:Videos]] | |||
[[Category:Graph Algorithms]] | [[Category:Graph Algorithms]] | ||
[[Category:All Pairs Shortest Paths]] | [[Category:All Pairs Shortest Paths]] | ||
[[Category:Shortest Paths Problems]] | |||
[[Category:Checkup]] | |||
== General information == | == General information == | ||
Line 25: | Line 24: | ||
'''Algorithmic problem:''' [[Single source shortest paths]] | '''Algorithmic problem:''' [[Single source shortest paths]] | ||
'''Prerequisities:''' For all <math> | '''Prerequisities:''' For all <math>a\in A</math>, it is <math>l(a) \geq 0</math>. | ||
'''Type of algortihm:''' loop | '''Type of algortihm:''' loop | ||
'''Auxiliary data:''' | '''Auxiliary data:''' | ||
# A temporary '''distance value''' <math>\delta(v) \in \R</math> for each node <math>v \in V</math>. At termination, it is <math>\delta(v) = \Delta(v)</math> for all <math>v \in V</math> where <math>\Delta(v)</math> is the shortest <math>(s,v)</math>-path. | # A temporary '''distance value''' <math>\delta(v) \in \mathbb{R}</math> for each node <math>v \in V</math>. At termination, it is <math>\delta(v) = \Delta(v)</math> for all <math>v \in V</math> where <math>\Delta(v)</math> is the shortest <math>(s,v)</math>-path. | ||
# A [[bounded priority queue]] <math>Q</math> of size <math>|V|-1</math>, which contains nodes from <math>V</math> and takes their <math>\delta</math>-values as keys. The node with minimal key is returned. | # A [[bounded priority queue]] <math>Q</math> of size <math>|V|-1</math>, which contains nodes from <math>V</math> and takes their <math>\delta</math>-values as keys. The node with minimal key is returned. | ||
Line 45: | Line 44: | ||
'''Break condition:''' | '''Break condition:''' | ||
* <math>Q = \ | * <math>Q = \emptyset</math>, which means that all nodes are reachable from <math>s</math> and have been processed; | ||
* otherwise, if <math>\delta(v) = +\infty</math> for the next node <math>v</math> of <math>Q</math>, which means that <math>\delta(v) = + \infty</math> for '''every''' node in <math>Q</math> and hence none of the nodes in <math>Q</math> is reachable from <math>s</math>. | * otherwise, if <math>\delta(v) = +\infty</math> for the next node <math>v</math> of <math>Q</math>, which means that <math>\delta(v) = + \infty</math> for '''every''' node in <math>Q</math> and hence none of the nodes in <math>Q</math> is reachable from <math>s</math>. | ||
Line 74: | Line 73: | ||
=== Correctness: === | === Correctness: === | ||
The first invariant is trivially maintained. So we will focus on the second and third invariants.<br> | The first invariant is trivially maintained. So we will focus on the second and third invariants.<br> | ||
Consider the moment immediately before the <math>i</math>-iteration. The core of the proof is to show that <math>\delta(v) = \Delta(v)</math> hold at that moment (and hence forever). For a contradiction, suppose there is an <math>(s,v)</math>-path <math>p</math> whose length is strictly less than <math>\delta(v)</math>. The third invariant implies that <math>p</math> has nodes in <math>Q</math> beside <math>v</math>. Let <math>u</math> denote the first such node on <math>p</math>. Then none of the nodes on the subpath of <math>p</math> from <math>s</math> to <math>u</math> belonged to <math>Q</math> at that moment (except for <math>u</math> itself, of course). Due to the [[ | Consider the moment immediately before the <math>i</math>-iteration. The core of the proof is to show that <math>\delta(v) = \Delta(v)</math> hold at that moment (and hence forever). For a contradiction, suppose there is an <math>(s,v)</math>-path <math>p</math> whose length is strictly less than <math>\delta(v)</math>. The third invariant implies that <math>p</math> has nodes in <math>Q</math> beside <math>v</math>. Let <math>u</math> denote the first such node on <math>p</math>. Then none of the nodes on the subpath of <math>p</math> from <math>s</math> to <math>u</math> belonged to <math>Q</math> at that moment (except for <math>u</math> itself, of course). Due to the [[[[basics of shortest paths#Subpath property of shortest paths|prefix property]], this subpath is a shortest <math>(s,u)</math>-path, so Invariant #3 implies <math>\delta(u) = \Delta(u)</math>. On the other hand, the specific choice of <math>v</math> implies <math>\delta(u) \geq \delta(v)</math>. In summary, the subpath of <math>p</math> from <math>s</math> to <math>u</math> is not shorter than <math>\delta(v)</math>. To obtain <math>l(p) < \delta(v)</math>, the subpath of <math>p</math> from <math>u</math> to <math>v</math> must have negative total length, which contradicts the prerequisite <math>l \geq 0</math>.<br> | ||
Now we know <math>\delta(v) = \Delta(v)</math>. Therefore, <math>v</math> fulfills the statement of the second invariant after the <math>i</math>-th iteration. Of course, the second invariant is not violated by any other node either, and is thus maintained.<br> | Now we know <math>\delta(v) = \Delta(v)</math>. Therefore, <math>v</math> fulfills the statement of the second invariant after the <math>i</math>-th iteration. Of course, the second invariant is not violated by any other node either, and is thus maintained.<br> | ||
For a node <math>w \in V</math> let <math>P_i (w)</math> denote the set of all <math>(s,w)</math>-paths such that no node (except for <math>w</math> itself) is in <math>Q</math> immediately after the <math>i</math>-th iteration. In particular, the statement of the third invariant means that <math>\delta(w)</math> is the length of a shortest path in <math>P_i (w)</math>. The induction hypothesis says that <math>\delta(w)</math> is the minimum length of all <math>(s,w)</math>-paths in <math>P_{i-1} (w)</math>. The difference <math>P_i (w) \setminus P_{i-1} (w)</math> consists of all <math>(s,w)</math>-paths such that <math>(v,w)</math> is the last arc and all nodes except for <math>v</math> and <math>w</math> | For a node <math>w \in V</math> let <math>P_i (w)</math> denote the set of all <math>(s,w)</math>-paths such that no node (except for <math>w</math> itself) is in <math>Q</math> immediately after the <math>i</math>-th iteration. In particular, the statement of the third invariant means that <math>\delta(w)</math> is the length of a shortest path in <math>P_i (w)</math>. The induction hypothesis says that <math>\delta(w)</math> is the minimum length of all <math>(s,w)</math>-paths in <math>P_{i-1} (w)</math>. The difference <math>P_i (w) \setminus P_{i-1} (w)</math> consists of all <math>(s,w)</math>-paths such that <math>(v,w)</math> is the last arc and all nodes except for <math>v</math> and <math>w</math> were not in <math>Q</math> anymore immediately before the current iteration. Therefore, the second step of the iteration incorporates <math>P_i (w) \setminus P_{i-1} (w)</math> in the computation of <math>\delta(w)</math> appropriately to maintain Invaraint #3. | ||
== Complexity == | == Complexity == | ||
'''Statement:''' The worst-case complexity is in <math>O( | '''Statement:''' The worst-case complexity is in <math>O(T(n)\cdot(n+m))</math>, where <math>n = |V|</math> and <math>m = |A|</math>, and <math>T(n)</math> is the worst-case complexity for extraction/inserting nodes in <math>Q</math>. | ||
'''Proof:''' Each node is inserted in and extracted from <math>Q</math> at most once, respectively, which gives <math>O(T(n) \cdot n)</math> in total. Also, each arc <math>(v,w) \in A</math> is touched at most once, namely | '''Proof:''' Each node is inserted in and extracted from <math>Q</math> at most once, respectively, which gives <math>O(T(n) \cdot n)</math> in total. Also, each arc <math>(v,w) \in A</math> is touched at most once, namely | ||
* in the initialization if <math>v = s</math>, | * in the initialization if <math>v = s</math>, | ||
* when <math>v</math> is extracted from <math>Q</math> otherwise. | * when <math>v</math> is extracted from <math>Q</math> otherwise. | ||
Therefore, all decrease-key operations require <math>O(T(n) \cdot m)</math> in total. | |||
< | |||
</ | |||
== Heuristic speed-up techniques == | == Heuristic speed-up techniques == | ||
# We do not need to insert all nodes except for <math>s</math> in <math>Q</math>. In fact, it suffices to initially insert the endnodes of the outgoing arcs of <math>s</math> and, during an iteration, to insert the nodes of the outgoing arcs of the node that is being extracted from <math>Q</math>. In a sense, the nodes of <math>Q</math> then constitute the "frontierline" of the algorithm. We choose another variant on Dijkstra's algorithm mainly for simplicity of presentation. | # We do not need to insert all nodes except for <math>s</math> in <math>Q</math>. In fact, it suffices to initially insert the endnodes of the outgoing arcs of <math>s</math> and, during an iteration, to insert the nodes of the outgoing arcs of the node that is being extracted from <math>Q</math>. In a sense, the nodes of <math>Q</math> then constitute the "frontierline" of the algorithm. We choose another variant on Dijkstra's algorithm mainly for simplicity of presentation. | ||
# Clearly, Dijkstra's algorithm also solves the single-source single-target case. In this case, Dijkstra may safely terminate once has been extracted from <math>Q</math>. In fact, the loop invariant implies <math>\delta(t) = \Delta(t)</math> from then on. This variant on Dijkstra's algorithm is sometimes called the '''early termination variant'''.[[File:Dijkstrabidirectional.png|350px|thumb|right|advantage of a bidirectional search]] | # Clearly, Dijkstra's algorithm also solves the single-source single-target case. In this case, Dijkstra may safely terminate once <math>t</math> has been extracted from <math>Q</math>. In fact, the loop invariant implies <math>\delta(t) = \Delta(t)</math> from then on. This variant on Dijkstra's algorithm is sometimes called the '''early termination variant'''.[[File:Dijkstrabidirectional.png|350px|thumb|right|advantage of a bidirectional search]] | ||
# In the single-source single-target case, two searches may be applied simultaneously: one from <math>s</math> on <math>G</math>, the other one from <math>t</math> on the [[Basic graph definitions#Transpose of a graph|transpose]] of <math>G</math>. This variant is called '''bidirectional search'''. It terminates once one node has been seen by both searches. Then either the concatenation of the paths to this node from both searches is a shortest <math>(s,t)</math>-path, or such a path may be found among the paths of the following kind: There is an arc <math>(v,w)\in A</math> such that <math>v</math> has been seen in the forward search from the source and <math>w</math> has been seen in the backward search from <math>t</math>. | # In the single-source single-target case, two searches may be applied simultaneously: one from <math>s</math> on <math>G</math>, the other one from <math>t</math> on the [[Basic graph definitions#Transpose of a graph|transpose]] of <math>G</math>. This variant is called '''bidirectional search'''. It terminates once one node has been seen by both searches. Then either the concatenation of the paths to this node from both searches is a shortest <math>(s,t)</math>-path, or such a path may be found among the paths of the following kind: There is an arc <math>(v,w)\in A</math> such that <math>v</math> has been seen in the forward search from the source and <math>w</math> has been seen in the backward search from <math>t</math>. | ||
# In a scenario where we perform a large number of searches on the same graph and arc lengths, we do not need to touch the whole graph in each search: | # In a scenario where we perform a large number of searches on the same graph and arc lengths, we do not need to touch the whole graph in each search: | ||
Line 128: | Line 94: | ||
## We also change the algorithm as suggested by the second point: terminate once <math>t</math> is processed. | ## We also change the algorithm as suggested by the second point: terminate once <math>t</math> is processed. | ||
## To avoid touching all nodes for initializing the <math>\delta</math>-values, we maintain sort of a '''version counter''', or '''time stamp''', for each node, which holds the ID of the last search that met this node. Whenever a node is met in a search and the nodes version counter does not equal the ID of the current search, the distance value of this node is regarded as <math>+ \infty</math> (no matter what its current value is).[[File:Dijkstragoaldirected.png|350px|thumb|right|the length of a non-goal-directed arc grows, the length of a neutral arc stays the same and the length of the goal-directed arc shriks]] | ## To avoid touching all nodes for initializing the <math>\delta</math>-values, we maintain sort of a '''version counter''', or '''time stamp''', for each node, which holds the ID of the last search that met this node. Whenever a node is met in a search and the nodes version counter does not equal the ID of the current search, the distance value of this node is regarded as <math>+ \infty</math> (no matter what its current value is).[[File:Dijkstragoaldirected.png|350px|thumb|right|the length of a non-goal-directed arc grows, the length of a neutral arc stays the same and the length of the goal-directed arc shriks]] | ||
# The early termination variant may be modified as follows: For [[Basics of shortest paths#(Admissible) node potentials|admissible node potentials]] <math>h:V \to \R</math>, replace length <math>\ell</math> by <math> | # The early termination variant may be modified as follows: For [[Basics of shortest paths#(Admissible) node potentials|admissible node potentials]] <math>h:V \to \mathbb{R}</math>, replace length <math>\ell</math> by <math>\ell_h</math> where <math>\ell_h(a) := \ell(a) + h(w) - h(v)</math> for each <math>a = (v,w) \in A</math>. This variant is usually called '''goal-directed search'''. The heuristic idea is that we (hopefully) reach <math> t</math> earlier because the arcs that roughly point towards <math>t</math> are shortened, and the arcs the roughly point in a direction away from <math>t</math> are lengthened. |
Latest revision as of 08:35, 14 January 2021
General information
Algorithmic problem: Single source shortest paths
Prerequisities: For all [math]\displaystyle{ a\in A }[/math], it is [math]\displaystyle{ l(a) \geq 0 }[/math].
Type of algortihm: loop
Auxiliary data:
- A temporary distance value [math]\displaystyle{ \delta(v) \in \mathbb{R} }[/math] for each node [math]\displaystyle{ v \in V }[/math]. At termination, it is [math]\displaystyle{ \delta(v) = \Delta(v) }[/math] for all [math]\displaystyle{ v \in V }[/math] where [math]\displaystyle{ \Delta(v) }[/math] is the shortest [math]\displaystyle{ (s,v) }[/math]-path.
- A bounded priority queue [math]\displaystyle{ Q }[/math] of size [math]\displaystyle{ |V|-1 }[/math], which contains nodes from [math]\displaystyle{ V }[/math] and takes their [math]\displaystyle{ \delta }[/math]-values as keys. The node with minimal key is returned.
Abstract view
Invariant: After [math]\displaystyle{ i \geq 0 }[/math] iterations:
- [math]\displaystyle{ Q }[/math] contains all nodes of [math]\displaystyle{ V }[/math] except [math]\displaystyle{ s }[/math] and [math]\displaystyle{ i }[/math] further nodes.
- For the nodes [math]\displaystyle{ v \in V }[/math] not in [math]\displaystyle{ Q }[/math], it is [math]\displaystyle{ \delta(v) = \Delta(v) }[/math].
- For the nodes [math]\displaystyle{ v \in V }[/math] in [math]\displaystyle{ Q }[/math], [math]\displaystyle{ \delta(v) }[/math] is the length of a shortest [math]\displaystyle{ (s,v) }[/math]-path that solely contains nodes not in [math]\displaystyle{ Q }[/math] (except for [math]\displaystyle{ v }[/math] itself, of course). As usual, this means [math]\displaystyle{ \delta(v) = +\infty }[/math] if there is no such path.
In particular, it is [math]\displaystyle{ \delta(v) \geq \Delta(v) }[/math] for each node [math]\displaystyle{ v \in V }[/math].
Variant: [math]\displaystyle{ i }[/math] increases by [math]\displaystyle{ 1 }[/math].
Break condition:
- [math]\displaystyle{ Q = \emptyset }[/math], which means that all nodes are reachable from [math]\displaystyle{ s }[/math] and have been processed;
- otherwise, if [math]\displaystyle{ \delta(v) = +\infty }[/math] for the next node [math]\displaystyle{ v }[/math] of [math]\displaystyle{ Q }[/math], which means that [math]\displaystyle{ \delta(v) = + \infty }[/math] for every node in [math]\displaystyle{ Q }[/math] and hence none of the nodes in [math]\displaystyle{ Q }[/math] is reachable from [math]\displaystyle{ s }[/math].
Induction basis
Abstract view:
- All nodes of [math]\displaystyle{ V }[/math] except [math]\displaystyle{ s }[/math] have to be members of [math]\displaystyle{ Q }[/math].
- Root [math]\displaystyle{ s }[/math] must have correct distance [math]\displaystyle{ \Delta(s) = 0 }[/math].
- The other nodes must meet Invariant #3.
Implementation:
- [math]\displaystyle{ \delta(s) := 0 }[/math];
- For all [math]\displaystyle{ a = (s,v) \in A }[/math], set [math]\displaystyle{ \delta(v) := l(a) }[/math].
- For all [math]\displaystyle{ v \in V\setminus\{s\} }[/math] with [math]\displaystyle{ (s,v) \notin A }[/math] set [math]\displaystyle{ \delta(v) := +\infty }[/math].
- Insert all nodes in [math]\displaystyle{ V\setminus\{s\} }[/math] into [math]\displaystyle{ Q }[/math].
Proof:
Obvious.
Induction step
Abstract view:
One node is extracted from [math]\displaystyle{ Q }[/math], and the distance values of the endnodes of its outgoing arcs are updated to meet Invariant #3.
Implementation:
- Extract the next node [math]\displaystyle{ v }[/math] from [math]\displaystyle{ Q }[/math].
- For each outgoing arc [math]\displaystyle{ a = (v,w) \in A }[/math] such that [math]\displaystyle{ w \in Q }[/math], set [math]\displaystyle{ \delta(w) := min\{\delta(w), \delta(v) + l(a)\} }[/math].
Correctness:
The first invariant is trivially maintained. So we will focus on the second and third invariants.
Consider the moment immediately before the [math]\displaystyle{ i }[/math]-iteration. The core of the proof is to show that [math]\displaystyle{ \delta(v) = \Delta(v) }[/math] hold at that moment (and hence forever). For a contradiction, suppose there is an [math]\displaystyle{ (s,v) }[/math]-path [math]\displaystyle{ p }[/math] whose length is strictly less than [math]\displaystyle{ \delta(v) }[/math]. The third invariant implies that [math]\displaystyle{ p }[/math] has nodes in [math]\displaystyle{ Q }[/math] beside [math]\displaystyle{ v }[/math]. Let [math]\displaystyle{ u }[/math] denote the first such node on [math]\displaystyle{ p }[/math]. Then none of the nodes on the subpath of [math]\displaystyle{ p }[/math] from [math]\displaystyle{ s }[/math] to [math]\displaystyle{ u }[/math] belonged to [math]\displaystyle{ Q }[/math] at that moment (except for [math]\displaystyle{ u }[/math] itself, of course). Due to the [[prefix property, this subpath is a shortest [math]\displaystyle{ (s,u) }[/math]-path, so Invariant #3 implies [math]\displaystyle{ \delta(u) = \Delta(u) }[/math]. On the other hand, the specific choice of [math]\displaystyle{ v }[/math] implies [math]\displaystyle{ \delta(u) \geq \delta(v) }[/math]. In summary, the subpath of [math]\displaystyle{ p }[/math] from [math]\displaystyle{ s }[/math] to [math]\displaystyle{ u }[/math] is not shorter than [math]\displaystyle{ \delta(v) }[/math]. To obtain [math]\displaystyle{ l(p) \lt \delta(v) }[/math], the subpath of [math]\displaystyle{ p }[/math] from [math]\displaystyle{ u }[/math] to [math]\displaystyle{ v }[/math] must have negative total length, which contradicts the prerequisite [math]\displaystyle{ l \geq 0 }[/math].
Now we know [math]\displaystyle{ \delta(v) = \Delta(v) }[/math]. Therefore, [math]\displaystyle{ v }[/math] fulfills the statement of the second invariant after the [math]\displaystyle{ i }[/math]-th iteration. Of course, the second invariant is not violated by any other node either, and is thus maintained.
For a node [math]\displaystyle{ w \in V }[/math] let [math]\displaystyle{ P_i (w) }[/math] denote the set of all [math]\displaystyle{ (s,w) }[/math]-paths such that no node (except for [math]\displaystyle{ w }[/math] itself) is in [math]\displaystyle{ Q }[/math] immediately after the [math]\displaystyle{ i }[/math]-th iteration. In particular, the statement of the third invariant means that [math]\displaystyle{ \delta(w) }[/math] is the length of a shortest path in [math]\displaystyle{ P_i (w) }[/math]. The induction hypothesis says that [math]\displaystyle{ \delta(w) }[/math] is the minimum length of all [math]\displaystyle{ (s,w) }[/math]-paths in [math]\displaystyle{ P_{i-1} (w) }[/math]. The difference [math]\displaystyle{ P_i (w) \setminus P_{i-1} (w) }[/math] consists of all [math]\displaystyle{ (s,w) }[/math]-paths such that [math]\displaystyle{ (v,w) }[/math] is the last arc and all nodes except for [math]\displaystyle{ v }[/math] and [math]\displaystyle{ w }[/math] were not in [math]\displaystyle{ Q }[/math] anymore immediately before the current iteration. Therefore, the second step of the iteration incorporates [math]\displaystyle{ P_i (w) \setminus P_{i-1} (w) }[/math] in the computation of [math]\displaystyle{ \delta(w) }[/math] appropriately to maintain Invaraint #3.
Complexity
Statement: The worst-case complexity is in [math]\displaystyle{ O(T(n)\cdot(n+m)) }[/math], where [math]\displaystyle{ n = |V| }[/math] and [math]\displaystyle{ m = |A| }[/math], and [math]\displaystyle{ T(n) }[/math] is the worst-case complexity for extraction/inserting nodes in [math]\displaystyle{ Q }[/math].
Proof: Each node is inserted in and extracted from [math]\displaystyle{ Q }[/math] at most once, respectively, which gives [math]\displaystyle{ O(T(n) \cdot n) }[/math] in total. Also, each arc [math]\displaystyle{ (v,w) \in A }[/math] is touched at most once, namely
- in the initialization if [math]\displaystyle{ v = s }[/math],
- when [math]\displaystyle{ v }[/math] is extracted from [math]\displaystyle{ Q }[/math] otherwise.
Therefore, all decrease-key operations require [math]\displaystyle{ O(T(n) \cdot m) }[/math] in total.
Heuristic speed-up techniques
- We do not need to insert all nodes except for [math]\displaystyle{ s }[/math] in [math]\displaystyle{ Q }[/math]. In fact, it suffices to initially insert the endnodes of the outgoing arcs of [math]\displaystyle{ s }[/math] and, during an iteration, to insert the nodes of the outgoing arcs of the node that is being extracted from [math]\displaystyle{ Q }[/math]. In a sense, the nodes of [math]\displaystyle{ Q }[/math] then constitute the "frontierline" of the algorithm. We choose another variant on Dijkstra's algorithm mainly for simplicity of presentation.
- Clearly, Dijkstra's algorithm also solves the single-source single-target case. In this case, Dijkstra may safely terminate once [math]\displaystyle{ t }[/math] has been extracted from [math]\displaystyle{ Q }[/math]. In fact, the loop invariant implies [math]\displaystyle{ \delta(t) = \Delta(t) }[/math] from then on. This variant on Dijkstra's algorithm is sometimes called the early termination variant.
- In the single-source single-target case, two searches may be applied simultaneously: one from [math]\displaystyle{ s }[/math] on [math]\displaystyle{ G }[/math], the other one from [math]\displaystyle{ t }[/math] on the transpose of [math]\displaystyle{ G }[/math]. This variant is called bidirectional search. It terminates once one node has been seen by both searches. Then either the concatenation of the paths to this node from both searches is a shortest [math]\displaystyle{ (s,t) }[/math]-path, or such a path may be found among the paths of the following kind: There is an arc [math]\displaystyle{ (v,w)\in A }[/math] such that [math]\displaystyle{ v }[/math] has been seen in the forward search from the source and [math]\displaystyle{ w }[/math] has been seen in the backward search from [math]\displaystyle{ t }[/math].
- In a scenario where we perform a large number of searches on the same graph and arc lengths, we do not need to touch the whole graph in each search:
- We change the algorithm as suggested by the first point: only keep the "frontierline" in [math]\displaystyle{ Q }[/math].
- We also change the algorithm as suggested by the second point: terminate once [math]\displaystyle{ t }[/math] is processed.
- To avoid touching all nodes for initializing the [math]\displaystyle{ \delta }[/math]-values, we maintain sort of a version counter, or time stamp, for each node, which holds the ID of the last search that met this node. Whenever a node is met in a search and the nodes version counter does not equal the ID of the current search, the distance value of this node is regarded as [math]\displaystyle{ + \infty }[/math] (no matter what its current value is).
- The early termination variant may be modified as follows: For admissible node potentials [math]\displaystyle{ h:V \to \mathbb{R} }[/math], replace length [math]\displaystyle{ \ell }[/math] by [math]\displaystyle{ \ell_h }[/math] where [math]\displaystyle{ \ell_h(a) := \ell(a) + h(w) - h(v) }[/math] for each [math]\displaystyle{ a = (v,w) \in A }[/math]. This variant is usually called goal-directed search. The heuristic idea is that we (hopefully) reach [math]\displaystyle{ t }[/math] earlier because the arcs that roughly point towards [math]\displaystyle{ t }[/math] are shortened, and the arcs the roughly point in a direction away from [math]\displaystyle{ t }[/math] are lengthened.