利用DeepSeek辅助Python求解Advent of Code 2025第11题 问题路径 第2部分

用DeepSeek优化Python解AOC路径

AI赋能编程语言挑战赛 10w+人浏览 223人参与

原题地址

第二问的路径很多,简单的罗列行不通,让DeepSeek帮助解决。

编写python程序找到所有从 svr 通向 out 同时访问了 dac 和 fft的路径数量,注意数据量较大,不能全都罗列,考虑分段计算,把结果叠加起来,比如svr到aaa有100条,从aaa到dac有200条,那么从svr到dac有20000条

他给出了如下程序,应该是解此类问题的通用方法,瞬间输出结果, 有15位数,提交后完全正确。但是多余考虑了成环的路径,其实本题不可能成环,否则就有无限的路径了

from collections import defaultdict, deque

def parse_input():
    """解析输入,构建有向图"""
    graph = defaultdict(list)
    
    with open('2511-input.txt', 'r') as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
                
            parts = line.split(':')
            if len(parts) < 2:
                continue
                
            source = parts[0].strip()
            targets = [t.strip() for t in parts[1].split()]
            graph[source] = targets
    
    return graph

def count_paths_with_required_nodes(graph, start, end, required_nodes):
    """
    计算从start到end且必须包含所有required_nodes的路径数量
    
    策略:分段计算,避免枚举所有路径
    """
    required_nodes = set(required_nodes)
    n = len(required_nodes)
    
    if n == 0:
        # 如果没有特殊要求节点,直接计算所有路径
        return count_all_paths(graph, start, end)
    
    # 第一步:找到所有可能经过这些必要节点的顺序
    # 对于2个节点,有2种可能的顺序:[dac, fft] 或 [fft, dac]
    required_list = list(required_nodes)
    node_orders = []
    
    # 生成所有可能的排列
    from itertools import permutations
    for perm in permutations(required_list):
        node_orders.append(list(perm))
    
    total_count = 0
    
    # 第二步:对每种顺序分别计算
    for order in node_orders:
        # 路径必须按此顺序访问这些节点
        # 将路径分段:start -> order[0] -> order[1] -> ... -> order[n-1] -> end
        segments = [start] + order + [end]
        
        segment_counts = []
        
        # 计算每个段落的路径数
        for i in range(len(segments) - 1):
            seg_start = segments[i]
            seg_end = segments[i + 1]
            
            # 计算从seg_start到seg_end的路径数
            # 注意:为了避免路径中包含其他required节点,需要临时修改图
            # 但在分段计算中,中间路径不应该包含后续的required节点
            
            count = count_paths_between(graph, seg_start, seg_end, 
                                        forbidden_nodes=set(order[i+1:]) if i < len(order) else set())
            if count == 0:
                # 这个分段没有路径,整个顺序无效
                segment_counts = None
                break
                
            segment_counts.append(count)
        
        if segment_counts:
            # 该顺序的总路径数 = 各段路径数的乘积
            order_count = 1
            for cnt in segment_counts:
                order_count *= cnt
            
            total_count += order_count
    
    return total_count

def count_paths_between(graph, start, end, forbidden_nodes=None):
    """
    计算从start到end的路径数量,使用动态规划避免指数爆炸
    可以包含循环检测
    """
    if forbidden_nodes is None:
        forbidden_nodes = set()
    
    # 使用拓扑排序处理有向无环图
    # 首先检查是否存在环
    if has_cycle(graph):
        # 如果有环,使用DP+记忆化搜索,但限制深度
        return count_paths_with_cycle(graph, start, end, forbidden_nodes)
    else:
        # 如果是DAG,使用拓扑排序
        return count_paths_dag(graph, start, end, forbidden_nodes)

def has_cycle(graph):
    """检查图中是否存在环"""
    visited = set()
    rec_stack = set()
    
    def dfs(node):
        visited.add(node)
        rec_stack.add(node)
        
        for neighbor in graph.get(node, []):
            if neighbor not in visited:
                if dfs(neighbor):
                    return True
            elif neighbor in rec_stack:
                return True
        
        rec_stack.remove(node)
        return False
    
    for node in graph:
        if node not in visited:
            if dfs(node):
                return True
    
    return False

def count_paths_dag(graph, start, end, forbidden_nodes):
    """计算DAG中从start到end的路径数"""
    # 拓扑排序
    indegree = defaultdict(int)
    for node in graph:
        for neighbor in graph[node]:
            indegree[neighbor] += 1
        if node not in indegree:
            indegree[node] = 0
    
    # 拓扑排序
    topo_order = []
    queue = deque([node for node in indegree if indegree[node] == 0])
    
    while queue:
        node = queue.popleft()
        topo_order.append(node)
        
        for neighbor in graph.get(node, []):
            indegree[neighbor] -= 1
            if indegree[neighbor] == 0:
                queue.append(neighbor)
    
    # DP计算路径数
    dp = defaultdict(int)
    dp[start] = 1
    
    # 按照拓扑顺序处理
    for node in topo_order:
        if node in forbidden_nodes and node != start and node != end:
            continue
            
        if dp[node] > 0:
            for neighbor in graph.get(node, []):
                if neighbor not in forbidden_nodes or neighbor == end:
                    dp[neighbor] += dp[node]
    
    return dp.get(end, 0)

def count_paths_with_cycle(graph, start, end, forbidden_nodes):
    """
    处理可能有环的图,使用记忆化搜索
    需要限制深度避免无限循环
    """
    memo = {}
    visited_in_path = set()
    
    def dfs(node, depth):
        if depth > 50:  # 限制最大深度
            return 0
            
        if node == end:
            return 1
            
        if (node, tuple(sorted(visited_in_path))) in memo:
            return memo[(node, tuple(sorted(visited_in_path)))]
        
        total = 0
        visited_in_path.add(node)
        
        for neighbor in graph.get(node, []):
            if neighbor in forbidden_nodes and neighbor != end:
                continue
                
            if neighbor not in visited_in_path:
                total += dfs(neighbor, depth + 1)
        
        visited_in_path.remove(node)
        memo[(node, tuple(sorted(visited_in_path)))] = total
        return total
    
    return dfs(start, 0)

def count_all_paths(graph, start, end):
    """计算从start到end的所有路径数(不考虑特殊节点要求)"""
    return count_paths_between(graph, start, end)

def main():
    graph = parse_input()
    
    # 检查是否包含必要的节点
    all_nodes = set(graph.keys())
    for neighbors in graph.values():
        all_nodes.update(neighbors)
    
    required_nodes = ['dac', 'fft']
    missing_nodes = [node for node in required_nodes if node not in all_nodes]
    
    if missing_nodes:
        print(f"图中缺少必要的节点: {missing_nodes}")
        return 0
    
    if 'svr' not in all_nodes:
        print("图中缺少起始节点 'svr'")
        return 0
    
    if 'out' not in all_nodes:
        print("图中缺少结束节点 'out'")
        return 0
    
    # 计算路径数
    result = count_paths_with_required_nodes(graph, 'svr', 'out', required_nodes)
    
    print(f"从 svr 到 out 且同时访问 dac 和 fft 的路径数量: {result}")
    return result

if __name__ == "__main__":
    main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值