特定类型图中的最长路径

Posted

技术标签:

【中文标题】特定类型图中的最长路径【英文标题】:Longest path in a particular type of graph 【发布时间】:2012-12-23 00:51:07 【问题描述】:

我知道longest path problem 对于一般图来说是 NP 难的。但是,我正在考虑一种特定类型的图,它由一个循环组成,加上循环的每个顶点上的一个附加边。例如,对于长度为 7 的循环,我们有如下图:

所有边都被加权(权重是实数,可以是正数或负数)。我想在这张图上找到最大的简单路径,其中路径的大小是路径上边权重的总和。

算法在循环的大小上应该是线性的。但任何想法都会受到赞赏。

【问题讨论】:

当然,这是从图中修剪死端的情况,然后找到权重最低的边,并将其两端作为最长(权重最高)的起点和终点) 链。 @paddy:如果权重不能为负数,那就可以了…… @paddy:我不太明白。你能说得更具体点吗? @becko:那改变问题;结果的偏移量将与路径中的边数成正比。 @becko 好吧,检查配对的简单算法是O(N^3)。您需要对循环进行预处理以获得O(1)中两点之间的距离。 【参考方案1】:

这可以简化为Maximum subarray problem 并在线性时间内解决。

    断开循环(在任何节点)。 将剩余图表的第二个副本附加到循环断开的点(我们可能会跳过最后一个节点)。 将修改后的 Kadane 算法应用于生成的节点列表。 如果找到的路径没有边,则在图中搜索权重最大的边。如果该边具有非负权重,则报告此单边路径。如果不是,如果不允许空路径,则无论如何报告此单边路径,如果允许,则报告空路径。

->

必要的 Kadane 算法修改:

    跟踪当前路径(子数组)中的节点数。当子数组具有N 或更多“循环”节点时,从尾部修剪节点。为了有效地修剪这些节点,我们需要一个可以报告其元素最小值的队列。将元素推入该队列,无论路径的头部前进(如果非负,则添加叶边权重),当路径尾部被修剪时弹出元素,并在当前路径重置为空路径的任何地方重置队列。该队列包含(不一定是简单的)路径的前缀长度,其中最小值为推进路径尾部提供了适当的位置。这样的队列可以实现为仅包含非递减值的双端队列,也可以实现为this 答案中提到的一对堆栈。 将路径长度重置为max(0, leaf_edge_weight),只要当前路径的长度低于零(而不是在原始 Kadane 算法中将其重置为零)。 在当前(非空)路径与最佳路径进行比较时,添加非负叶边缘权重(对应于头节点)。

【讨论】:

我也在准备这样的答案:) 但是我没有解决的部分是当子数组有超过 N 个节点时如何有效地从尾部修剪节点。你能详细说明一下吗? @j_random_hacker:这部分肯定需要更多解释。谢谢。【参考方案2】:

在循环中选择一个链接。最长的路径要么通过该链接,要么不通过该链接,因此让我们找出任何一种情况下的最佳答案,然后选择其中最好的一个。

如果最长路径不经过循环链接,则删除该链接以生成树。从叶子向上计算,在每个节点上,该节点下的最长路径,以及从该节点到任何后代的最长路径。在每个节点上,您可以通过查看其子节点的答案来计算答案。根部的答案为您提供了最长的路径。

如果最长的路径确实经过您选择的链接,则它必须包含从链接一端顺时针方向走的部分和从链接另一端逆时针方向走的部分。这两个的长度加起来不超过一加上构成循环的链接数。对于 i = 1 来限制计算链路每一侧的顺时针和逆时针路径的成本并保持运行最大值。通过该链接的最长路径的长度为,对于一些 k,最长路径顺时针方向最多 k 个链接,最长路径逆时针方向最多 Nk 个链接(可能有一些类似成本的摆弄 - ve 链接成本存在)。因此,您可以找到通过您选择的链接的最长路径,成本也是 O(n)。

计算两个案例,每个案例的成本为 O(n),然后选择最佳的,总成本为 O(n)

【讨论】:

您是否考虑了负权重?如果在选择的节点和最长的路径之间,有一些具有巨大负权的边怎么办?它会找到与节点在同一侧的最长路径(不是全局最长路径)。 当您说“您可以通过选择任意节点作为根节点并查看必须通过根节点的最长路径来显示这一点”,您的意思是“通过根”?因为整个树中最长的路径不一定会经过一些任意选择的根(这毕竟只是一个任意选择的顶点)。但在那种情况下,你的论点似乎并不能解释为什么会找到最长的路径——“半路径”似乎是 w.r.t.选择的根。该算法似乎是合理的,但我还不明白为什么它必须有效! @Dukeling 在树的 -ve 权重的情况下我错了。我已将该部分替换为对 DAG 解决方案的引用。 @j_random_hacker 我未能重建我被告知的事实的证明——至少在 +ve 权重的情况下。我被告知想象在选择的第一个点之前举起树。最长路径任一端的两个点中的至少一个必须从那里垂下,距离最长路径的至少一半。如果有一个点比这两个点中的任何一个离原点更远,我想你可以结合所谓的最长路径来创建更长的路径,这是一个矛盾。 @Dukeling - 哎呀,一棵树没有被引导,所以我又尝试了一次树案例。【参考方案3】:

最长的路径几乎肯定在两个外部顶点之间。几乎可以肯定,覆盖循环中的所有顶点也是必要的。

因此,您想使用 DFS 在 O(N) 中绘制循环。然后计算当前循环排列的长度。加上从循环中的第一个点到它的外部的距离以及最后一个点到它的外部的距离。这为您提供了实际的路径长度,您将其与循环长度分开存储。

增加第一个点和最后一个点的索引(可以在 O(1) 中完成),删除现在从第一个点指向最后一个点的边的长度。然后再次添加外部长度。重复直到你覆盖了所有的顶点。由于您存储和更新路径长度而不是每次都实际重新计算它(这需要(O(N ^ 2)),因此可以在O(N)中完成。

这允许在 O(N) 中遍历循环。但是,它不是一个精确的算法。这需要检查您是否不应该将 first+i 和/或 last-j 用于某些 i,j 。要完全检查这一点,基本上需要 O(N^2)。

不过,您可能会在 O(N log N) 左右通过巧妙地确定可能出现这些边缘情况的情况来完成此操作。我怀疑精确的线性算法是否可行。

【讨论】:

以上是关于特定类型图中的最长路径的主要内容,如果未能解决你的问题,请参考以下文章

在有向无环图中求最长路径

在图中找到最长的路径

树径问题 最长路问题。。

树的直径(最长路) 的详细证明(转)

hiho_1050_树中的最长路

如何在加权图中找到最长的路径?