路径还原

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


最早接触这个问题是在自己学习最短路问题的时候,那个时候学了几个最短路以为自己很牛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之中了,再利用时可以方便地被使用。如果

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


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


②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专题或者本专题里找。



在 Windows 系统中,公共桌面(也称为“所有用户桌面”)通常用于存储所有用户共享的快捷方式和文件。恢复或访问公共桌面路径可以通过编程方式或系统工具实现。 ### 通过编程方式访问公共桌面路径 在 C# 中,可以通过调用 Windows API 函数 `SHGetFolderPath` 来获取公共桌面路径。此方法依赖于 `shfolder.dll` 提供的功能,并使用特定的常量 `CSIDL_COMMON_DESKTOPDIRECTORY` 来标识公共桌面目录: ```csharp using System; using System.Runtime.InteropServices; using System.Text; public class DesktopPath { [DllImport("shfolder.dll", CharSet = CharSet.Auto)] private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken, int dwFlags, StringBuilder lpszPath); private const int MAX_PATH = 260; private const int CSIDL_COMMON_DESKTOPDIRECTORY = 0x0019; public static string GetAllUsersDesktopFolderPath() { StringBuilder sbPath = new StringBuilder(MAX_PATH); SHGetFolderPath(IntPtr.Zero, CSIDL_COMMON_DESKTOPDIRECTORY, IntPtr.Zero, 0, sbPath); return sbPath.ToString(); } public static void Main() { string publicDesktopPath = GetAllUsersDesktopFolderPath(); Console.WriteLine("公共桌面路径: " + publicDesktopPath); } } ``` ### 通过系统路径访问公共桌面路径 公共桌面的默认路径通常是: ``` C:\Users\Public\Desktop ``` 在某些系统配置或本地化版本中,路径可能有所不同,例如: ``` C:\Users\Öffentlich\Desktop # 德语版 Windows ``` 可以通过资源管理器直接访问此路径[^2]。 ### 通过注册表查找公共桌面路径 桌面路径通常存储在注册表中,可以通过访问注册表键值来查找公共桌面路径。注册表路径如下: ``` HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders ``` 在该路径下,可以查找与公共桌面相关的键值,例如: ``` Common Desktop ``` 通过读取该键值,可以获取公共桌面的实际路径。 ### 恢复公共桌面路径 如果公共桌面路径被修改或丢失,可以通过以下方法恢复: 1. **重新创建公共桌面文件夹**:在默认路径(如 `C:\Users\Public\Desktop`)下手动创建缺失的文件夹。 2. **重置注册表键值**:将注册表中的 `Common Desktop` 键值恢复为默认值。 3. **使用系统文件检查工具**:运行 `sfc /scannow` 命令以修复系统文件可能的损坏。 ###
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值