The algorithm is linked to the proof by providing invariants at each step of the algorithm: show that the algorithm maintains those invariants (before and after each step) and you show that your algorithm is correct. |
Yes. Your idea provides a quicker proof, though for the proof to be rigorous I still need to provide plenty of detail:
Shorter second proof (addresses the algorithm directly without proving any formal theorem):
Suppose at some stage in the loop, shortestPath[destination] has elements {node_n, node_(n-1), ..., node_1, destination} such that
node_n -> node_(n-1) -> ... -> node_1 -> destination
is the ending portion of a shortest path from 'source' to 'destination' (base case: when shortestPath[destination] = {destination} only, then it is obviously true). The next iteration of the loop gives
shortestPath[destination] = {parent[node_n], node_n, node_(n-1), ..., node_1, destination}.
Suppose
parent[node_n] -> node_n -> node_(n-1) -> ... -> node_1 -> destination
is NOT the ending portion of a shortest path from 'source' to 'destination'. Then there exists a shortest path p from 'source' to 'destination' through node_n with z as parent node of node_n, where
z != parent[node_n]. By definition, parent[node_n] is the parent node of node_n along some shortest path q from 'source' through node_n to some destination node d. Let r the sub-path of q
from 'source' to node_n, let s be the sub-path of q from node_n to d, let t be the sub-path of p from 'source' to node_n, and let y be the sub_path of p from node_n to 'destination'.
Denote distance(y) to be the distance along a path y, and denote xUy to be the union of two paths x and y, given that x ends where y begins. We claim that distance(r) <= distance(t).
Suppose instead that distance(r) > distance(t). Then since both t and r are paths that go from 'source' to node_n, and s starts at node_n (and ends at d), we have
distance(tUs) = distance(t) + distance(s) < distance(r) + distance(s) = distance(rUs) = distance(q).
Thus tUs is a shorter path than q. But tUs is a path from 'source' to d though node_n, contradicting the fact that q is a shortest path such path. Thus we must have distance(r) <= distance(t).
But this means that
distance(rUy) = distance(r) + distance(y) <= distance(t) + distance(y) = distance(tUy) = distance(p).
Since rUy is a path from 'source' to 'destination' through node_n, and p is a shortest such path, then the above must be strict equality, which means that rUy is also a shortest path from
'source' to 'destination' through node_n. But rUY has parent[node_n] as parent of node_n, contradicting the assumption that
parent[node_n] -> node_n -> node_(n-1) -> ... -> node_1 -> destination
is not the ending portion of a shortest path from 'source' to 'destination'. Hence that assumption cannot be true, which means that
shortestPath[destination] = {parent[node_n], node_n, node_(n-1), ..., node_1, destination}
given by the next iteration of the loop is also the ending portion of a shortest path from 'source' to 'destination', completing the inductive step. Hence every iteration of the loop creates
a longer ending portion of a shortest path from 'source' to 'destination', and when the loop exits with 'source' as the last parent (this must always be possible otherwise parent[node_n] could not exist
to begin with), we finally get a shortest path from 'source' to 'destination', completing the proof of the algorithm's correctness.