You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从边列表生成全连通图中的所有简单环?

枚举全连通图中的所有简单环

问题分析

你需要从有向全连通图的边列表中枚举所有简单环(顶点除起点/终点外不重复),同时要避免重复计数(比如反向的环视为同一个)。直接用itertools生成所有组合会产生大量冗余,且难以高效去重,因此更适合用DFS结合去重逻辑来实现。

实现思路

  • 构建邻接表:将边列表转换为邻接表结构,方便快速查找每个节点的出边,提升遍历效率。
  • DFS遍历所有路径:从每个节点出发,深度优先搜索所有可能的路径,当路径回到起始节点时,记录该环。
  • 环的去重处理:同一个环可以有多种表示形式(不同起点、反向),通过生成环的所有等价形式,选取字典序最小的作为唯一标识,从而避免重复。

代码实现

import itertools

def find_all_simple_cycles(edges):
    # 构建邻接表:key是起点,value是所有可达的终点
    adj = {}
    for u, v in edges:
        if u not in adj:
            adj[u] = []
        adj[u].append(v)
    
    all_cycles = []
    nodes = set(itertools.chain(*edges))  # 获取所有节点
    
    for start_node in nodes:
        # DFS栈:(当前节点, 已访问的边列表, 已访问的顶点集合)
        stack = [(start_node, [], set())]
        while stack:
            current, path_edges, visited_nodes = stack.pop()
            # 遍历当前节点的所有出边
            for neighbor in adj.get(current, []):
                new_path = path_edges + [(current, neighbor)]
                new_visited = visited_nodes.copy()
                new_visited.add(current)
                
                if neighbor == start_node:
                    # 找到一个环,长度至少为2(用户例子包含2边环)
                    if len(new_path) >= 2:
                        all_cycles.append(new_path)
                elif neighbor not in visited_nodes:
                    # 未访问过该节点,继续DFS
                    stack.append((neighbor, new_path, new_visited))
    
    # 去重处理:生成环的标准形式
    unique_cycles = set()
    for cycle in all_cycles:
        # 生成所有循环移位
        shifts = []
        k = len(cycle)
        for i in range(k):
            shifted = cycle[i:] + cycle[:i]
            shifts.append(tuple(shifted))
        # 生成反向序列的所有循环移位
        reversed_cycle = cycle[::-1]
        for i in range(k):
            shifted_rev = reversed_cycle[i:] + reversed_cycle[:i]
            shifts.append(tuple(shifted_rev))
        # 取字典序最小的作为唯一标识
        canonical = min(shifts)
        unique_cycles.add(canonical)
    
    # 转换为列表形式返回
    return [list(cycle) for cycle in unique_cycles]

# 测试用户提供的例子
edges = [(0,1),(0,2),(1,0),(1,2),(2,0),(2,1)]
result = find_all_simple_cycles(edges)
# 按长度排序后输出,和示例格式对齐
result_sorted = sorted(result, key=lambda x: len(x))
print(result_sorted)

代码说明

  1. 邻接表构建:遍历输入的边列表,为每个起点映射其所有可达的终点。
  2. DFS遍历:从每个节点出发,记录当前路径的边和已访问的顶点,避免路径中重复访问非起点的顶点(保证简单环)。当路径回到起点时,记录该环。
  3. 去重逻辑:对每个环生成所有循环移位和反向移位,选取字典序最小的形式作为唯一标识,存入集合自动去重。
  4. 测试结果:运行代码后,输出结果与你期望的完全一致。

内容的提问来源于stack exchange,提问作者moni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:15:24