原题地址 。
第二问的路径很多,简单的罗列行不通,让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()
用DeepSeek优化Python解AOC路径

550

被折叠的 条评论
为什么被折叠?



