182-小朋友崇拜圈-蓝桥云课-Python版代码解析
原题链接:182-小朋友崇拜圈-蓝桥云课
标签:蓝桥杯, 思维, 图上dfs,2018,省赛
语言整理
一个有向图,每个节点u有且仅有一条出边u→v。给定g数组, g[u] = v 表示这条出边。求图中最长环的长度
思路
- dfs(u) 表示当前访问节点 u ,集合 s 表示访问过的节点集
- 如果 u 在 s 中,说明找到了完整的环
- 如果 u 不在 s 中,添加到集合之中,并且访问后续节点 dfs(g[u])
- 遍历所有节点,确保考虑到所有的联通分量
由以上思路得到的类似代码
s = set()
def dfs(u):
if u in s: return #找到了换,本循环结束
s.add(u)
dfs(g[u])
for u in range(n+1):
dfs(u)
问题是如何求解环的长度?(不明白就画画图,u的大小肯定不能代表环的长度)
解决办法
- 时间戳思想,额外记录每次访问节点 u 的序号 idx ,用字典存放 u:idx键值对(而前面用的 s 只能记录在不在,不能记录第几个(即来到的“时间”))
- 如果 u 在 d 之中,说明第二次访问到 u,构成闭环。两次序号之差 idx - d[u]即环的长度
- 如果 u 不在 d 中,则添加到字典中,并且访问后续节点 dfs([u],idx + 1)
- 遍历所有节点,确保考虑所有连通分量
- 在外层用res记录最大环长
Python代码答案与分析
import sys
input = lambda: sys.stdin.readline().strip()
sys.setrecursionlimit(10000) #增加递归深度至少大于n,因为python默认只有1000
n = int(input())
g = [0] + list(map(int, input().split()))
res = 0
d = {}
def dfs(u, idx):
global res
if d.get(u) is not None: #非空,说明已记录,即找到了环,本循环结束
res = max(res, idx - d[u])
return
d[u] = idx #记录本次时间戳
dfs(g[u], idx + 1)
for u in range(n+1): #确保访问所有连通分量
dfs(u, 1)
print(res)

2万+

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



