Chapter 9
■
From a to B with edsger and Friends
204
situation where we know
exactly where we’re going. It introduces a
potential function, or
heuristic h(
v), which is our
best guess
for the remaining distance,
d(
v,
t). As you’ll see in a minute, Dijkstra’s algorithm “falls out” of A* as a special
case, when
h(
v) = 0. Also, if by magic we could set
h(
v) =
d(
v,
t), the algorithm would march directly from
s to
t.
So, how does it work? We define the modified edge weights to get a telescoping sum, like we did in Johnson’s
algorithm (although you should note that the signs are switched here):
w’(
u,
v) =
w(
u,
v) -
h(
u) +
h(
v). The telescoping
sum ensures that the shortest path will still be shortest (like in Johnson’s) because all path lengths are changed by
the same amount,
h(
t) -
h(
s). As you can see, if we set the heuristic to zero (or, really, any constant),
the weights are
unchanged.
It should be easy to see how this adjustment reflects our intention to reward edges that go in the right direction
and penalize those that don’t. To each edge weight, we add the
drop in potential (the heuristic), which is similar to
how gravity works. If you let a marble loose on a bumpy table, it will start moving in a direction that will decrease its
potential (that is, its potential energy). In our case, the algorithm will be steered in directions
that cause a drop in the
remaining distance—exactly what we want.
The A* algorithm is equivalent to Dijkstra’s on the modified graph, so it’s correct if
h is
feasible, meaning that
w’(
u,
v) is nonnegative for all nodes
u and
v. Nodes are scanned in increasing order of
D[
v] -
h(
s) +
h(
v), rather than
simply
D[
v]. Because
h(
s) is a common constant, we
can ignore it and simply add h(
v) to our existing priority. This
sum is our best estimate for the shortest path from
s to
t via
v. If
w’(
u,
v) is feasible,
h(
v) will also be a
lower bound on
d(
v,
t) (see Exercise 9-14).
One (very common) way of implementing all of this would be to use something like the original dijkstra and
simply add
h(
v) to the priority when pushing a node onto the heap. The original distance estimate would still be
available in D. If we want to simplify things, however,
only using the heap (as in idijkstra), we need to actually use
the weight adjustment so that for an edge (
u,
v), we subtract
h(
u) as well. This is the approach I’ve taken in Listing 9-10.
As you can see, I’ve made sure
to remove the superfluous h(
t) before returning the distance. (Considering the
algorithmic punch that the a_star function is packing, it’s pretty short and sweet, wouldn’t you say?)
Do'stlaringiz bilan baham: