给定一个无向循环图,我想通过广度优先搜索或深度优先搜索找到所有可能的遍历。给出一个图作为邻接列表:
A-BC
B-A
C-ADE
D-C
E-C
所以来自根 A 的所有 BFS 路径都是:
{ABCDE,ABCED,ACBDE,ACBED}
对于 DFS:
{ABCDE,ABCED,ACDEB,ACEDB}
我将如何以一种有意义的方式在算法上生成这些遍历?我想可以生成字母的所有排列并检查它们的有效性,但这对我来说似乎是最后的手段。
任何帮助,将不胜感激。
给定一个无向循环图,我想通过广度优先搜索或深度优先搜索找到所有可能的遍历。给出一个图作为邻接列表:
A-BC
B-A
C-ADE
D-C
E-C
所以来自根 A 的所有 BFS 路径都是:
{ABCDE,ABCED,ACBDE,ACBED}
对于 DFS:
{ABCDE,ABCED,ACDEB,ACEDB}
我将如何以一种有意义的方式在算法上生成这些遍历?我想可以生成字母的所有排列并检查它们的有效性,但这对我来说似乎是最后的手段。
任何帮助,将不胜感激。
BFS 应该很简单:每个节点都有一定的深度可以找到它。在您的示例中,您在深度 0 处找到 A,在深度 1 处找到 B 和 C,在深度 2 处找到 E 和 D。在每个 BFS 路径中,您将拥有深度为 0 (A) 的元素作为第一个元素,然后是深度 1(B 和 C)的元素,然后是深度 2(E 和 D)的元素的任何排列,等等...如果您查看示例,您的 4 个 BFS 路径与该模式匹配。A 始终是第一个元素,然后是 BC 或 CB,然后是 DE 或 ED。您可以将其推广到具有更深深度的节点的图。要找到它,您只需要 1 个非常便宜的 Dijkstra 搜索。
在 DFS 中,您没有很好的深度分离,这使得 BFS 变得简单。我没有立即看到与上述算法一样高效的算法。您可以通过遍历图形和回溯来设置图形结构并构建路径。在某些情况下,这不是很有效,但对于您的应用程序来说可能就足够了。
除了您实际执行所有可能的 DFS 和 BFS 遍历的明显方式之外,您可以尝试这种方法:
步骤 1. 在从根 A 开始的 dfs 遍历中,像这样转换当前访问节点的邻接列表: 首先从列表中删除节点的父节点。其次生成调整列表中剩余节点的所有排列。
因此,如果您在来自节点 A 的节点 C,您将执行以下操作:
C -> ADE transform into C -> DE transform into C -> [DE, ED]
第 2 步。在第 1 步之后,您有以下转换后的 adj 列表:
A -> [CB, BC]
B -> []
C -> [DE, ED]
D -> []
E -> []
现在您从 (A,0) 开始启动处理,其中对中的第一项是遍历路径,第二项是索引。假设我们有两个队列。一个 BFS 队列和一个 DFS 队列。我们将这对放入两个队列中。
现在我们重复以下操作,首先是一个队列,直到它为空,然后是另一个队列。
我们将第一对从队列中弹出。我们得到 (A,0)。节点 A 映射到 [BC, CB]。所以我们生成了两条新路径(ACB,1)和(ABC,1)。将这些新路径放入队列中。
将其中的第一个从队列中取出以获得 (ACB,1)。索引为 1,因此我们查看路径字符串中的第二个字符。这是 C。节点 C 映射到 [DE, ED]。
我们根据我们正在处理的队列生成新路径,基于上述并将它们放入队列中。因此,如果我们正在处理 BFS 队列,我们将放入 (ACBDE,2) 和 (ACBED,2)。我们队列的内容现在是:(ABC,1)、(ACBDE,2)、(ACBED,2)。
我们从队列中弹出 (ABC,1)。生成 (ABC,2) 因为 B 没有孩子。并获取队列:(ACBDE,2), (ACBED,2), (ABC,2) 等等。在某些时候,我们最终会得到一堆索引不包含在路径中的对。例如,如果我们得到 (ACBED,5),我们知道这是一条完成的路径。