【问题标题】:Find cycles in a graph that don't contain smaller cycle within it在图中查找不包含较小循环的循环
【发布时间】:2020-11-06 20:14:55
【问题描述】:

鉴于图的边缘,我希望在 python 中创建一个算法来查找其中没有其他循环的所有循环,我已经尝试了几天的各种想法,但没有 100% 的可靠性。

例如,

该图的边如下:

[[0,1],[2,1],[0,2],[0,3],[3,1],[3,2]]

并且有 7 个可能的不同循环/循环:

[[0, 2, 1, 0], [0, 3, 2, 1, 0], [0, 3, 1, 0], [0, 2, 3, 1, 0], [0, 3, 1, 2, 0], [0, 3, 2, 0], [1, 3, 2, 1]]

但是循环[0,3,2,1,0] 中嵌入了循环[0,2,1,0][0,3,2,0]。同样,[0,2,3,1,0] 中嵌入了循环 [0,3,2,0][0,3,1,0][0,3,1,2,0][1,3,2,1] 也是如此。

因此,我的 python 程序应该过滤掉所有这些并给出

[[0,2,1,0],[0,3,1,0],[0,3,2,0]]

其中没有其他循环的循环。

【问题讨论】:

标签: python algorithm data-structures graph computer-science


【解决方案1】:

您已确定所有周期。对于确定最小循环,节点顺序无关紧要:最小循环由其节点集唯一标识。

将每个节点列表转换为一个集合。制作列表中没有子集的集合的新列表。

cycle_list = [
    [0, 2, 1, 0],
    [0, 3, 2, 1, 0],
    [0, 3, 1, 0],
    [0, 2, 3, 1, 0],
    [0, 3, 1, 2, 0],
    [0, 3, 2, 0],
    [1, 3, 2, 1]
]

set_list = [set(c) for c in cycle_list]
min_cycle = [c for c in set_list if c!= super
             and not any(super < c for super in set_list)
             ]
print(min_cycle)

输出:

[{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}]

如果您希望循环按节点顺序排列,我相信您可以将四个解决方案(1、2、3、1 也是一种解决方案)映射回原始列表。

【讨论】:

  • @MateenUlhaq 这些节点按该顺序连接。你在哪里迷茫?它甚至列在原始问题中。
【解决方案2】:

编辑:这个方法解决了一个稍微不同的问题,但也许你可以根据你的具体情况调整它。我会在未来的某个时候修复答案。


此方法运行dfs() 以列出来自特定start 节点的所有候选周期。 was_traversed() 用于检查当前路径中是否已遍历特定路径。然后,在cycles() 方法中修剪掉“重复”循环。

def cycles(graph, start):
    paths = {tuple(sorted(xs)): xs for xs in dfs(graph, [start])}
    return paths.values()

def dfs(graph, path):
    for node in graph[path[-1]]:
        if was_traversed(path, path[-1], node):
            continue
        if node == path[0]:
            yield path + [node]
            continue
        yield from dfs(graph, path + [node])

def was_traversed(path, a, b):
    query = sorted([a, b])
    return any(
        sorted([x, y]) == query
        for x, y in zip(path[:-1], path[1:])
    )

测试:

>>> graph = {
...     0: [1, 2, 3],
...     1: [0, 2, 3],
...     2: [0, 1, 3],
...     3: [0, 1, 2],
... }

>>> for cycle in dfs(graph, [0]):
...     print(cycle)
[0, 1, 2, 0]
[0, 1, 2, 3, 0]
[0, 1, 3, 0]
[0, 1, 3, 2, 0]
[0, 2, 1, 0]
[0, 2, 1, 3, 0]
[0, 2, 3, 0]
[0, 2, 3, 1, 0]
[0, 3, 1, 0]
[0, 3, 1, 2, 0]
[0, 3, 2, 0]
[0, 3, 2, 1, 0]

>>> for cycle in cycles(graph, 0):
...     print(cycle)
[0, 2, 1, 0]
[0, 3, 2, 1, 0]
[0, 3, 1, 0]
[0, 3, 2, 0]

【讨论】:

  • 你省略了边缘 (2, 1);检查原始帖子。
猜你喜欢
  • 2018-05-15
  • 2020-04-19
  • 1970-01-01
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 2016-03-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多