路径还原

最短路中的路径还原问题:


最早接触这个问题是在自己学习最短路问题的时候,那个时候学了几个最短路以为自己很牛B了,也是稍微了解了

下如何在DK最短路算法中还原路径,可是当今天遇到一个BFS需要用到路径还原,真的是绞尽了脑汁2个小时多才把

AC代码给写了出来,这时才认识到自己是有多么的自负,所以决定写下这篇BLOG以供大家学习,也算是自己对知识

的一个总结吧!

路径还原一直也是最短路问题中的一个常见问题,所以由于某些题的需要,我将在这篇文章中为童鞋们详细讲解这

个问题。


首先,路径还原的意思就是将最短路那条路径记录下来以供使用(如输出最短路的路径)。


这里我将这个问题分的更细,将为大家讲解不同的最短路解法的路径还原方法。我将它们总结为了下面3种:

①最短路算法的路径还原

②DFS求最短路的路径还原

③BFS求最短路的路径还原

另外还会在最后补充路径还原时,如果还需要记录下每次状态转移时的动作时该怎么做以及当点是由(x,y)唯一确定,而不是由单一的编号确定时该怎么记录呢?(看不懂请往后看)


最短路的问题一般都是用这3种方法来求解,其中①仅适用于图的最短路,而DFS和BFS却能求解各种不同形式的最

优解,我们也可以形象的理解为求最短路。下面依次讲解这几个问题:


①最短路算法的路径还原:

理解了最短路算法的童鞋应该明白,这几个算法都是大同小异,其实质上都是贪心的结果,所以每一次松弛操作都是

一次贪心的操作。

在这几个算法中,我们普遍使用辅助数组d[i]来记录i点当前已知(或目前可以求出)的最短路。所以每进行一次松弛

操作都会使d[i]的数值更加接近结果,直到所有松弛操作完成便是最终所求结果,那么我们可以这样想,我们可以使

用另一个辅助数组prv[]来记录当前的最短路路径,具体实现为prv[i]=j代表了i是从j走来的,即当前i的最短路是通过从j

走到i得到的,我们把j叫做i的前驱节点,如此,随着松弛操作的最终完成(也就是最终的最短路的解出),prv[i]=j便

代表着i真正的最短路是通过从j走到i得到的。另外只要将prv[起点]的值初始化为一个特定值,这里我们用-1就可以

很好的将这条路径输出来了。

vector<int> path;
int t = end;     //这里end代表终点
for (; t != -1; t = prv[t])       //每次将当前的位置加入path直到到尽头-1,且-1不会被加入path
	path.push_back(t);
reverse(path.begin(), path.end());   //由于path是按从终点到起点的顺序加入的,所以需要反转


是的,仅需要再通过这简短的几行代码便可以顺利的将最短路径存于path之中了,再利用时可以方便地被使用。如果

觉得这几行代码难以理解的童鞋们可以看如下图片:

路径还原_第1张图片

看完这幅图估计大家也都能理解了,最短路算法的路径还原就讲到这里。


②DFS求最短路的路径还原

DFS中路径还原是比较麻烦的,到现在我还没有想出有什么好的解决方法,只有特定情况的题我才会还原路径,本来

想上网查查然后给大家分享的,可是一时间也找不到。。。只怪本人能力有限,以后想到了好的方法一定给补上,请

谅解。

只有当DFS搜到的第一条满足条件的路便是所求答案的解时才能直接记录路径(因为找到之后不会再会被其他的走法

覆盖)。

这里我直接给出一个例题,因为也不难,所以也不做过多解释,请大家自行画图(DFS解答树)体会体会。下面给出

这篇文章的链接:点击打开链接


③BFS求最短路的路径还原

BFS与DFS差别最大的一点便是在BFS中每个点(或者说每个状态)都只会入一次队,所以我们仍然可以仿效第①类

的做法,用一个辅助数组prv[]来记录路径,并且prv[i]的值被确定之后就不存在再次被覆盖的可能,因为每个点只会入

一次队嘛,正好我们记录的操作在入队的时候进行。之后的做法就和第①类没有区别了。



然后谈一谈我们在上面遗留的问题,路径还原时,如果还需要记录下每次状态转移时的动作时该怎么做,我的语言表

达能力也不算很强,所以也猜到了很多人会不理解这句话。

举个通俗的例子,假如在移动时(即状态转移时)你可以跳也可以走也可以用跑的,这3种移动法就可以当成是3种不

同的动作,不同的动作会有不同的影响,我们需要记录下的不仅仅是最优解时经过了哪些地点,还要记下每次移动分

别是通过什么样的动作来实现的。再举个例子,在走迷宫时可以往上下左右4个方向走,那么上下左右这4个便是4个

不同的动作。

这时我们便需要prv[i]中记录2个值,一个是前驱节点j,另一个是从j到i的动作。这个问题也很容易解决,只要写个结

构体就行了不是吗?

另一个问题当点是由(x,y)确定,而不是单一的编号确定时该怎么记录,这句话应该比较容易理解,当求城市间的

最短路时,不同的城市肯定是由一个不同的的编号来唯一确定的,可是如果在一个矩阵中,不同的点由一对(x,y)

确定时该怎么办呢?对比prv[i]=j代表j为i的前驱节点,是不是可以将prv定义成一个二维数组(当然前提是不会超过内

存限制),然后在prv[x1][y1]中记录2个值x2,y2,此时就可以很好的做到路径的记录了。


说这么多不如自己去实践一番,这里我仍然给出一个例题,将会用到上面给大家说的技巧:点击打开链接

题解大家可以在我的BFS专题或者本专题里找。



你可能感兴趣的:(ACM,路径还原)