图的最短路径都会写,那么最长路径呢?
最短路径是最经典的必学图论问题。Dijkstra 处理非负权图,Bellman-Ford 可以处理负权边,还能发现负权环。学到这里,很自然会冒出一个问题:既然有最短路径,那有没有最长路径?如果有,能不能把松弛操作里的 min 换成 max,把最短路径算法改一改就用?
这个问题表面上很对称,实际并不对称。最长路径不是一个“最短路径的反向版本”,而是会逼着我们重新确认“路径”到底允许什么、环怎么处理、答案是否一定有限。
最短路、path 和 walk
在最短路径里,我们通常想找从 \(s\) 到 \(t\) 的一条总代价最小的路线。如果所有边权非负,Dijkstra 可以用贪心方式逐步确定当前最短的点;如果存在负权边,Dijkstra 的前提会坏掉,但 Bellman-Ford 仍然可以通过多轮松弛处理。
于是看上去,最长路径也可以类似地定义:从 \(s\) 到 \(t\),找一条边权总和最大的路线。最短路径的松弛是如果 \(d[v] > d[u] + w(u,v)\) 就更新,那么最长路径似乎只要改成如果 \(d[v] < d[u] + w(u,v)\) 就更新。
这个想法只在某些受限场景下成立。
在图论里,path 和 walk 是有区别的。walk 只要求相邻顶点之间有边,可以重复经过顶点和边;simple path 则不允许重复经过顶点。中文里都可能被叫作“路径”。日常说“从 A 到 B 的路径”,通常不太区分是否允许重复经过同一个点。但图论和算法里,这个区别非常关键。通常提到最短路径问题,算法求解的是 walk,即允许重复。从实现上看,常见的最短路算法通常并不会在状态里记录“已经访问过哪些顶点”。Dijkstra 的状态是到每个点的当前最短距离,Bellman-Ford 也是不断对边做松弛。它们并没有显式禁止一条候选路线重复经过某个点。
最短路能转化成最长路吗?
在最短路径场景下,如果是正权图,那么 path 还是 walk 没有区别,因为一定不会重复走边浪费权重。若有负数边,但不成环,那么 Bellman-Ford 仍可处理。但最短路径怕负权环(在无向图里则是一条负边就够),因为绕一圈代价更小,可以一直降到任意低,答案不存在;反过来,最长 walk 怕的是正权环,因为绕一圈收益更大,可以一直涨到 \(+\infty\)。这和最短路径里的负权环是对称的。
所以,反过来看,只要图里存在正环(在无向图里,则是有正边权,并且允许重复行走),那么最长 walk 就会变成无界问题。并不能简单的转化就行了。
不过,如果不存在会影响答案的正权环(比如全图权重都是负数),这时最长路就确实可以转化成最短路了。做法很简单。把每条边的权重 \(w(e)\) 变成 \(-w(e)\),原图中的最长 walk 就对应新图中的最短 walk。原图里的正权环会变成新图里的负权环,因此可以用 Bellman-Ford 的负权环检测逻辑处理。
最长 simple path 是另一个问题
那如果要求解的是最长简单路径呢?从 \(s\) 到 \(t\),找一条不重复经过顶点的路径,使得总权重最大。
这个定义避免了正权环导致的无穷大。即使图里有正权环,由于不能重复经过顶点,也不可能无限绕圈。问题总是有有限答案。
但这个问题要困难得多。最短路算法之所以能只维护 \(d[v]\),是因为到达 \(v\) 之后,过去怎么来的通常可以被压缩成一个距离值。最长 simple path 不行。你到达 \(v\) 时已经访问过哪些点,会决定后面还能走哪些边。两个状态即使当前顶点相同,只要访问集合不同,后续空间也可能完全不同。
如果把访问集合也放进状态,可以做类似动态规划的搜索,但状态数量通常是指数级的。这个问题可以和 Hamiltonian Path 规约。给定一个无权图,如果它有 \(n\) 个顶点,那么它存在一条长度为 \(n-1\) 的 simple path,当且仅当它存在一条经过所有顶点一次的 Hamiltonian path。假如我们能高效求出一般图上的最长 simple path,就能判断 Hamiltonian Path 是否存在。后者是 NP-complete 问题,因此一般图上的最长 simple path 是 NP-hard 的。
所以,“最长路径可以取负变成最短路径”这句话只有在特定语义下成立。它不能拿来解决一般图上的最长简单路径。反过来我们还发现,如果最短路也强制只能选 simple path,那么有负环时它也不能做,会变成困难问题。

总结:最短路无负环则可用经典算法求解,且求出的既是最短 path 也是最短 walk;有负环则经典算法求出的 walk 不存在,会任意小、path 存在但是求解困难;最长路也一样,但他不能处理的是正环
特例:DAG
重要例外是 DAG,也就是有向无环图。在 DAG 上没有环,walk 和 simple path 的区别基本消失,也不会出现通过绕正权环把答案刷到无穷大的情况。
这时最长路径可以按拓扑序做动态规划。设 \(dp[v]\) 表示从起点 \(s\) 到 \(v\) 的最长路径长度,那么对每条边 \((u,v)\) 做类似 \(dp[v] = \max(dp[v], dp[u] + w(u,v))\) 的更新即可。因为拓扑序保证处理 \(v\) 之前,所有可能到达 \(v\) 的前驱都已经处理过了。
DAG 上的最长路径不只是一个理论特例。项目调度里的关键路径就是典型应用:任务之间有依赖关系,每个任务有耗时,依赖图天然是 DAG。整个项目的完成时间由最长的依赖链决定,而不是由所有任务耗时简单相加决定。
这类场景里,最长路径不仅可解,而且是非常自然的建模方式。

浙公网安备 33010602011771号