我有一张图表,我试图找到最长的路径,但我不确定如何去做。我使用Data.Graph
中的标准Graph
和Edge
类型,图表是使用buildG
函数生成的。我最初的想法是使用dfs
来执行深度优先搜索,但这产生了一个Forest
对象,我不确定如何操作。
如果它完全有帮助(我很抱歉我不能打印这个,showForest
只显示字符串),这是我图上dfs
命令的输出:< / p>
[Node {rootLabel = 87, subForest = [Node {rootLabel = 82, subForest = [Node {rootLabel = 70, subForest = []},Node {rootLabel = 83, subForest = [Node {rootLabel = 66, subForest = [Node {rootLabel = 72, subForest = [Node {rootLabel = 88, subForest = []}]}]},Node {rootLabel = 79, subForest = [Node {rootLabel = 69, subForest = [Node {rootLabel = 85, subForest = []},Node {rootLabel = 84, subForest = [Node {rootLabel = 86, subForest = []},Node {rootLabel = 73, subForest = [Node {rootLabel = 81, subForest = []}]}]}]}]}]},Node {rootLabel = 89, subForest = []}]}]}]
我找到了一些不同的函数来查找通过树的最长路径,例如在此answer中,但它们仅适用于Tree
s,而不适用于Forest
s,而我我不确定是否有可能在两者之间进行转换。
谢谢!
答案 0 :(得分:3)
正如Shersh在他们的回答中解释的那样,深度优先搜索不足以解决您的问题(如果是,您可以使用您链接的答案中的generalFold
,例如,重建最长的路径在森林的每棵树上)。另一种方法是从Data.Graph
切换到 fgl ,它提供各种各样的图算法,包括广度优先搜索。请注意,The Haddock documentation的FGL相当简洁,因此您还需要查阅package homepage提供的有用的用户指南。在下面的演示中,我将使用bft
函数来获取图表的广度优先生成树,这应该足以让您入门:
GHCi> import Data.Graph.Inductive.Graph
GHCi> import Data.Graph.Inductive.PatriciaTree
GHCi> import Data.Graph.Inductive.Query.BFS
GHCi> :{
GHCi| test :: UGr
GHCi| test = mkUGraph [1..7] [(1,3),(1,2),(2,4),(3,5),(2,6),(5,2),(5,7)]
GHCi| :}
GHCi> prettyPrint test
1:()->[((),2),((),3)]
2:()->[((),4),((),6)]
3:()->[((),5)]
4:()->[]
5:()->[((),2),((),7)]
6:()->[]
7:()->[]
GHCi> bft 1 test
[[1],[2,1],[3,1],[4,2,1],[6,2,1],[5,3,1],[7,5,3,1]]
生成树本质上是从节点到所有可到达节点的路径列表。例如,如果您只想找到一条长度最大且不关心绘图的路径,那么您只需要:
GHCi> import Data.Ord
GHCi> import Data.List
GHCi> maximumBy (comparing length) (bft 1 test)
[7,5,3,1]
如果你关心抽奖,你需要做一些像groupBy
这样的事情,但这并不会从根本上变得更加困难。
答案 1 :(得分:2)
我将首先解释dfs
的作用。正如您在评论中提到的那样,您使用了buildG
函数,因此我也会在答案中使用它。
dfs
有两个参数:图形和根节点列表。然后dfs
从列表中的每个顶点编号开始运行深度优先搜索,从列表中的那些节点返回可到达顶点的Tree
。例如:
Tree
的列表,其中根标签为1
且subforest为空。Tree
的列表,其中根标签为1
,而subforest列表为2作为根标签。Tree
的列表,其中根标签为{{1和subforest是列表,其中包含两个树,相应地以2和3作为根标签。以下 ghci 会话中演示了所有这些示例(甚至更多示例):
1
但是,不幸的是,λ: let g = buildG (1,1) []
λ: dfs g [1]
[Node {rootLabel = 1, subForest = []}]
λ: dfs g [2]
*** Exception: Ix{Int}.index: Index (2) out of range ((1,1))
λ: let g = buildG (1,2) [(1,2)]
λ: dfs g [1]
[Node {rootLabel = 1, subForest = [Node {rootLabel = 2, subForest = []}]}]
λ: dfs g [2]
[Node {rootLabel = 2, subForest = []}]
λ: let g = buildG (1,3) [(1,2), (1,3)]
λ: dfs g [1]
[Node {rootLabel = 1, subForest = [Node {rootLabel = 3, subForest = []},Node {rootLabel = 2, subForest = []}]}]
无法帮助您完成任务:从给定的顶点找到最远的顶点。在算法运行的方式中,它无法解决这些问题。假设你有4个顶点和边的图:
1→2,2→3→4→4→4
从1开始路径最长的顶点是3(此路径有2条边)。但dfs
会根据您指定的边缘顺序返回不同的结果。
dfs
这不是特定实施的问题。这就是λ: let g = buildG (1,4) [(1,2), (1,4), (2,3), (3,4)]
λ: dfs g [1]
[Node {rootLabel = 1, subForest = [Node {rootLabel = 4, subForest = []},Node {rootLabel = 2, subForest = [Node {rootLabel = 3, subForest = []}]}]}]
λ: let g = buildG (1,4) [(1,4), (1,2), (2,3), (3,4)]
λ: dfs g [1]
[Node {rootLabel = 1, subForest = [Node {rootLabel = 2, subForest = [Node {rootLabel = 3, subForest = [Node {rootLabel = 4, subForest = []}]}]}]}]
的工作原理。在一般情况下,您无法使用dfs
来解决您的特定问题。此外,这个问题无法通过重新排列列表中的边缘来修复,因为您不知道如何重新排列它们。
您真正需要使用的是dfs
算法 - 广度优先搜索。不幸的是,它没有在bfs
库中实现。所以你需要从零实现整个算法或在某处找到实现(这里有一些讨论:Traversing a graph breadth first, marking visited nodes in Haskell)。
答案 2 :(得分:0)
应注意,图中最长的路径与最长路径不同 在生成树中。图形可以有许多生成树,而这些树没有 有相同的高度。 duplode提供的btf代码可以正确找到生成树中最长的路径。
例如,duplode中的图表答案
mkUGraph [1..7] [(1,3),(1,2),(2,4),(3,5),(2,6),(5,2),(5,7)]
比建议[1,3,5,7]
的路径更长,路径为[1,3,5,2,6]
。
一个更简单的例子
mkUGraph [1,2,3] [(1,2),(1,3),(2,3)]
使用FGL btf 1
将产生生成树[[1], [3,1], [2,1]]
,最长路径为[1,2,3]
(并且本身就是生成树)。
一般来说,找到最长的路径并不是微不足道的(实际上是NP难的)但是可以使用拓扑排序的节点相当简单的折叠来完成DAG。