You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在DFS算法中实现约束条件以查找符合规则的欧洲城市路径

解决按字母顺序+不重复国家的DFS路径查找问题

嘿,Jop!你的这个按字母顺序探索欧洲城市路径的需求很有意思,咱们一步步来调整你的DFS实现,把两个核心约束加进去。

首先,先指出你基础代码里的一个小bug:递归调用的时候你传的是root而不是neighbour,这会导致程序一直卡在当前节点循环,根本不会遍历邻居,这个得先修正。

接下来,咱们聚焦两个关键约束的实现:


1. 核心约束的处理逻辑

你的两个核心约束是:

  • 路径字母顺序:每一步的城市首字母必须是上一步的下一个字母(a→b→c…)
  • 不重复国家:路径里不能出现同一个国家的城市

要实现这两个约束,我们需要给DFS函数添加额外的跟踪参数:

  • current_path:保存当前已经走过的城市路径,用来判断下一个城市的首字母要求
  • visited_countries:保存已经去过的国家,用来避免重复访问同一国家

2. 修改后的完整DFS实现

先假设你的图里每个节点是(城市名, 国家名)这样的元组(方便获取首字母和国家),比如示例图:

# 示例图:键是(城市名, 国家名),值是相邻的城市节点列表
graph = {
    ("Amsterdam", "Netherlands"): [("Berlin", "Germany"), ("Brussels", "Belgium")],
    ("Berlin", "Germany"): [("Amsterdam", "Netherlands"), ("Cannes", "France"), ("Budapest", "Hungary")],
    ("Brussels", "Belgium"): [("Amsterdam", "Netherlands"), ("Cannes", "France")],
    ("Cannes", "France"): [("Berlin", "Germany"), ("Brussels", "Belgium"), ("Dublin", "Ireland")],
    ("Budapest", "Hungary"): [("Berlin", "Germany"), ("Dublin", "Ireland")],
    ("Dublin", "Ireland"): [("Cannes", "France"), ("Budapest", "Hungary")]
}

然后是修改后的DFS函数:

def dfs(graph, current_path, visited_countries):
    # 可选:如果当前路径达到目标长度(比如到Z),可以直接输出结果并返回
    print("找到有效路径片段:", current_path)
    
    # 计算下一个需要的首字母:路径长度为n时,下一个字母是第n+1个字母(a对应长度0,b对应长度1)
    next_char = chr(ord('a') + len(current_path))
    
    current_node = current_path[-1]
    for neighbour in graph[current_node]:
        # 约束1:跳过已经访问过的国家的城市
        neighbour_country = neighbour[1]
        if neighbour_country in visited_countries:
            continue
        
        # 约束2:检查邻居城市的首字母是否符合要求(忽略大小写)
        neighbour_first_char = neighbour[0][0].lower()
        if neighbour_first_char != next_char:
            continue
        
        # 满足所有约束,进入递归探索
        current_path.append(neighbour)
        visited_countries.add(neighbour_country)
        
        # 递归遍历邻居
        dfs(graph, current_path, visited_countries)
        
        # 回溯:移除当前邻居,尝试其他分支(关键!不然会影响后续路径探索)
        current_path.pop()
        visited_countries.remove(neighbour_country)

# 初始化:从所有首字母为A的城市出发
start_nodes = [node for node in graph if node[0][0].lower() == 'a']
for start in start_nodes:
    initial_path = [start]
    initial_visited_countries = {start[1]}
    dfs(graph, initial_path, initial_visited_countries)

3. 关键细节解释

  • 约束检查的位置:在遍历每个邻居后、递归调用前,先过滤掉不符合条件的邻居(国家已访问或首字母不对),这样能避免无效的递归分支,提升效率。
  • 回溯机制:递归返回后,要把当前邻居从路径和国家集合中移除,这样程序才能探索其他可能的路径(比如从Berlin出发,既可以去Cannes,也可以去Budapest,回溯后就能切换分支)。
  • 首字母判断逻辑:通过len(current_path)来计算下一个需要的字母——比如路径长度为1(已经有A开头的城市),下一个就需要B开头的,以此类推,完美匹配你的a→b→c…的需求。
  • 替代原来的visited集合:用visited_countries代替城市的visited,因为你的约束是不能重复国家,而不是不能重复城市(同一国家的不同城市也不能去)。

4. 测试和扩展

运行上面的代码,你会看到所有符合要求的路径片段被输出。如果想找到最长的有效路径,可以在函数里加一个判断:当没有符合条件的邻居时,记录当前路径作为候选最长路径。

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

火山引擎 最新活动