蓝桥杯day9——树和图的DFS&&BFS
链表模拟数组
看本篇需要了解,链表的数组模拟
图和树的存储
- 邻接矩阵,空间是 O ( n 2 ) O(n^2) O(n2)
- 一般使用邻接表来存储
-
数据结构
h[N]:表头,每个节点的连通的起始点
e[M]:存储节点的值
ne[M]:对应e[M],next指针的作用
idx:用于节点迭代 -
方法:用于构建图和树
##@parm a, b,值为a的节点通往b节点 def add(a, b) : global idx e[idx] = b ne[idx] = h[a] h[a] = idx idx += 1
-
DFS
模板
def dfs(u) :
st[u] = True # 记录该节点已经被遍历过了
i = h[u] # 取出正在遍历节点的表头指针
while i != -1 : # 通过指针迭代层级角度迭代
j = e[i]
if not st[j] :
dfs (j) # 深入下一个节点
i = ne[i]
例题:树的重心
给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。
请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
输入格式
第一行包含整数 n,表示树的结点数。
接下来 n−1 行,每行包含两个整数 a 和 b,表示点 a 和点 b 之间存在一条边。
输出格式
输出一个整数 m,表示将重心删除后,剩余各个连通块中点数的最大值。
数据范围
1≤n≤10^5
输入样例
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
输出样例:
4
N = 100010
M = N * 2
h = [-1] * N
e = [-1] * M
ne = [-1] * M
idx = 0
def add(a, b) :
global idx
e[idx] = b
ne[idx] = h[a]
h[a] = idx
idx += 1
ans = N
st = [False] * N
def dfs(u) :#对节点u进行搜索,返回以u为根节点连通块的数量
global ans
size, sum = 0, 1#size记录u的连通分支的最大数量,sum记录以u为根节点连通块数量
st[u] = True
i = h[u]
while i != -1 :
j = e[i]
i = ne[i]
if st[j] : continue#说明j节点的所有分支已经被计算过,这里是它的父节点
s = dfs (j)#连通分支的节点个数
size = max(s, size)
sum += s
size = max(size, n - sum)#考虑非子节点的连通分支
ans = min(size, ans)
return sum
n = int(input())
for i in range(n - 1) :
a, b = map(int, input().split())
add(a, b)
add(b, a)
dfs(1)
print(ans)
e[i] 存储的是第i个节点的标号,一般来说其值是惟一的标定一个节点,一般操作和遍历都是以其值作为标准的,通过h和ne来记录位置,e来进行操作
通过st数组来记录节点是否被访问过
BFS
模板
def bfs() :
que = collections.deque()
d = [-1] * N
que.appendleft(1)
d[1] = 0
while len(que) :
t = que.pop()
i = h[t]
while i != -1 :
j = e[i]
i = ne[i]
if d[j] == -1 :
d[j] = d[t] + 1
que.appendleft(j)
return d[n]
例题:图中点的层次
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环。
所有边的长度都是 1,点的编号为 1∼n。
请你求出 1 号点到 n 号点的最短距离,如果从 1 号点无法走到 n 号点,输出 −1。
输入格式
第一行包含两个整数 n 和 m。
接下来 m 行,每行包含两个整数 a 和 b,表示存在一条从 a 走到 b 的长度为 1 的边。
输出格式
输出一个整数,表示 1 号点到 n 号点的最短距离。
数据范围
1≤n,m≤10^5
输入样例:
4 5
1 2
2 3
3 4
1 3
1 4
输出样例:
1
import collections
N = 100010
M = 2 * N
h = [-1] * N
e = [-1] * M
ne = [-1] * M
idx = 0
def add(a, b) :
global idx
e[idx] = b
h[b] = h[a]
h[a] = idx
idx += 1
def bfs() :
que = collections.deque()
d = [-1] * N
que.appendleft(1)
d[1] = 0
while len(que) :
t = que.pop()
i = h[t]
while i != -1 :
j = e[i]
i = ne[i]
if d[j] == -1 :
d[j] = d[t] + 1
que.appendleft(j)
return d[n]
n, m = map(int, input().split())
for i in range(m) :
a, b = map(int, input().split())
add(a, b)
print(bfs())
总结
数组模拟领接表存储图和树的操作还得多做做,熟能生巧。需要注意:
e标志着实际的节点,h和ne都是起着模拟链表指针的作用。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!