上一篇博文我们提到了图的最短路径问题:两个顶点间的最短路径该如何寻找?其实这个问题不应该叫“最短”路径问题,而应该叫“最便宜”路径问题,因为有时候我们会为图中的边赋权(weight),也叫权重,相当于经过一条边的“代价”,一般为正数。比如下图(边旁的数字即该边的权重)
如果单纯考虑一条路径上边的条数,那么从v0到v6的最短路径应该是:v0-v3-v6。但是如果考虑边的权重,从v0到v6的“最便宜”路径应该是:v0-v1-v4-v6,其总权重为3(路径中所有边的权重之和),而如果走v0-v3-v6的路径,总权重将是11。
边有权重的图我们称之为赋权图,反之称为无权图,赋权图显然可以比无权图应用于更多场合,比如用赋权图来表示城市间公路,权重越大路况越差,或者权重越大,过路费用越高等等。
其实不考虑权重的最短路径问题就是所有边的权重都是1的“最便宜”路径问题,比如将上图的所有边去掉权重后的无权图也可以这样表示:
方便起见,我们就将“最便宜”路径称为最短路径。
接下来让我们先从简单的无权情况开始,看看如何找两个顶点间的最短路径。不过到了这一步,一件有意思的事情需要说明一下,那就是:找X到Y的最短路径,比找X到所有顶点的最短路径更慢(有权无权都是如此)。
出现这个情况的原因我们可以简单的分析一波:找X到Y的最短路径,最直接的做法就是令程序从X出发沿着可行的边不断的走,直到走到Y处为止,但是当走到Y处时,没人能保证刚刚走的那条路就是最短的,除非你走遍了整个图的顶点,换句话说,你要确定走到Y处且走的路径是最短的,你就得走遍所有顶点,而且在这个过程中你必须不断记录各个路径的长度,不然当你发现到一个顶点有多条路径时怎么比较它们呢?所以,你要找X到Y的最短路径,你就得找出X到所有顶点的最短路径。
当然,也存在专门寻找点对点最短路径的思路,但是目前来说,单独找X到Y的最短路径不会比找X到所有顶点的最短路径更快,所以我们接下来探讨的问题其实都是:单源最短路径问题。即给定一个起点(源),求出其与所有顶点的最短路径。有了到所有顶点的最短路径,我们自然也就有了到给定顶点Y的最短路径。
对无权图进行单源最短路径寻找的思路,就是我们上面所说的“最直接的做法”。为了更方便讲解,我们假定若存在边(A,B),则B是被A“指向”的顶点。那么对无权图进行单源最短路径寻找就是这样的:
首先,我们将起点的路径长设为0,其他顶点路径长设为负数(也可以是其他不可能的值,图例中用?表示),下例以v1作为起点
接着我们将起点所指向的顶点的路径长设为1,可以肯定的是,只有被路径长为0的起点所指向的顶点的路径长为1,本例中即v3和v4:
接下来,我们将路径长为1的顶点(v3和v4)所指向的顶点的路径长设为2,同样可以肯定,只有被路径长为1的顶点所指向的顶点的路径长为2。不过此时会遇到一个问题:v3是v4所指向的顶点,但