暑假,小恒要去一些城市旅游。有的城市之间有公路,有的城市之间没有公路,如下图。为了省钱和方便出行规划,小衡希望在出发前知道任意两个城市之间的最短距离。上图中4个城市共有8条道路,道路上的数字表示道路的长度。请注意,这些道路是单向的。我们现在需要求任意两个城市之间的最短距离,即求任意两点之间的最短路径。这个问题也被称为“多源最短路径”问题。现在我们需要一个数据结构来存储图的信息,我们还是可以用一个4*4的矩阵(二维数组e)来存储。例如城市1到城市2的距离为2,则将e[1][2]的值设置为2。如果城市2无法到达城市4,则将e[2][4]的值设置为∞.另外,这里规定一个城市对自己是0,比如e[1][1]是0,如下。现在回到问题:如何找到任意两点之间的最短路径?通过前面的学习,我们知道可以通过深度优先或者广度优先搜索找到两点之间的最短路径。因此,通过进行n2次深度或广度优先搜索,即每两点进行一次深度或广度优先搜索,即可得到任意两点之间的最短路径。但是还有别的办法吗?我们想一想,根据我们以往的经验,如果我们想缩短任意两点之间的距离(比如从顶点a到顶点b),只能引入第三个点(顶点k),并通过这个Vertexk中转是a->k->b,可以缩短原来顶点a到顶点b的距离。那么1~n中的哪一点是过境点k呢?有时甚至更短,不仅要经过一个点,还要经过两个或多个点,即a->k1->k2b->或a->k1->k2…->k->i…->b.比如上图中4号城市到3号城市(4->3)的距离e[4][3]原本是12,如果只经过1号城市(4->1->3),距离会缩短为11(e[4][1]+e[1][3]=5+6=11)。其实1号城到3号城也可以通过2号城中转,这样1号城到3号城的距离就缩短为5(e[1][2]+e[2][3]=2+3=5)。那么如果同时中转1号和2号城市,4号城市到3号城市的距离会进一步缩短为10。通过这个例子,我们发现每个顶点都有可能缩短其他两个顶点之间的距离。好的,让我们概括一下这个问题。当任意两点之间不允许有第三个点时,这些城市之间的最短距离就是初始距离,如下。如果只允许通过1号顶点,如何求任意两点之间的最短距离?判断e[i][1]+e[1][j]是否小于e[i][j]即可。e[i][j]表示从顶点i到顶点j的距离。e[i][1]+e[1][j]表示顶点i到顶点1,再从顶点1到顶点j的距离之和。其中i是1~n循环,j也是1~n循环,代码实现如下。for(i=1;i<=n;i++){for(j=1;j<=n;j++){if(e[i][j]>e[i][1]+e[1][j])e[i][j]=e[i][1]+e[1][j];}}更新任意两点之间只允许经过1号顶点的最短距离如:通过上图我们发现,在只经过顶点1的情况下,顶点3到顶点2(e[3][2]),顶点4到顶点2(e[4][2]])和顶点4到顶点3的距离(e[4][3])被缩短。接下来继续求在只允许通过1和2两个顶点的情况下,任意两点之间的最短距离。怎么做?在经过顶点1只允许任意两点间距离最短的结果下,我们需要判断经过顶点2是否可以缩短顶点i和顶点j的距离,即判断e[i][2]+e[2][j]小于e[i][j],代码实现如下。//在顶点1之后for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(e[i][j]>e[i][1]+e[1][j])e[i][j]=e[i][1]+e[1][j];//在第二个顶点之后for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(e[i][j]>e[i][2]+e[2][j])e[i][j]=e[i][2]+e[2][j];在只允许顶点1和2的情况下,任意两点之间的最短距离更新如下:由上图可知,只允许通过在顶点1有中转的情况下,中转通过顶点1和2为此处允许,使e[1][3]和e[4][3]之间的距离更短。同理,继续求任意两点之间的最短距离,同时只允许通过顶点1、2、3传递。任意两点之间的最短距离更新为:***Allvertexesareallowedtobeas中转,最终任意两点之间的最短距离为:整个算法过程虽然说起来麻烦,但是代码实现很简单,核心代码只有五行:for(k=1;k<=n;k++)对于(i=1;i<=n;i++)对于(j=1;j<=n;j++)如果(e[i][j]>e[i][k]+e[k][j])e[i][j]=e[i][k]+e[k][j];这段代码的基本思想是:一开始只允许通过顶点1,然后只允许通过顶点1和2...允许通过1~n的所有顶点,并找到任意两点之间的最短距离。一句话就是:从第i个顶点到第j个顶点,只经过前k个点的最短距离。其实这是一种“动态规划”思想,我们将在《啊哈!算法2——伟大思维闪耀时》中详细讨论。该算法的完整代码如下:#include
