一、图论理论基础
图的种类:有向图 和 无向图。
度:无向图中有几条边连接该节点,该节点就有几度。
连通性
连通图:无向图 中,任何两个节点可以相互到达。
强连通图:有向图 中,任何两个节点可以相互到达。
连通分量:无向图 中的 极大 连通子图称之为该图的一个连通分量。
强连通分量:有向图 中 极大 强连通子图称之为该图的强连通分量。
二、深搜理论基础(DFS)
深搜(dfs)和广搜(bfs)区别
dfs是可一个方向一直搜索下去;
bfs是先把本节点连接的所有节点遍历一遍,然后走到下一个节点时,再遍历一遍。
深搜三部曲
1. 确定递归函数 和 参数;
2. 确定终止条件;
3. 处理目前搜索节点出发的路径。(for 循环遍历 目前搜索节点 所能到的所有节点)
Note:dfs 遇到黄河回头的过程就是回溯算法。
"""
DFS模板
"""
def DFS(graph, s):
stack = []
stack.append(s)
# 创建一个哈希表存储遍历过的节点
seen = {}
seen.add(s)
# 当栈不为空时
while (len(stack) > 0):
# 从栈中弹出最后一个元素
vertex = queue.pop()
# 找到vertex的邻接节点
nodes = graph[vertex]
# 遍历节点
for w in nodes:
# 如果这些邻接节点没有走过,将其添加到队列中
if w not in seen:
stack.append(w)
seen.add(w)
print(vertex)
三、98. 所有可达路径
题目链接:98. 所有可达路径 (kamacoder.com)
文章讲解:代码随想录 (programmercarl.com)——98. 所有可达路径
"""
邻接矩阵写法
"""
# 1. 确定递归函数和参数
# graph: 存当前的图
# x: 遍历节点
# n: 终点
# path: 1节点到终点的路径
# result: 收集符合条件的路径
def dfs(graph, x, n, path, result):
# 2. 确定终止条件,当前遍历节点 x 为终点 n
if x == n:
result.append(path.copy())
return
# 3. 处理目前搜索节点出发的路径
# 遍历 x 连接的所有节点
for i in range(1, n + 1):
# 找到 x 指向的节点
if graph[x][i] == 1:
# 将选中的 x 所指向的节点加入到单一路径中
path.append(i)
# 进入下一层递归
dfs(graph, i, n, path, result)
# 回溯,撤销本节点
path.pop()
def main():
# 读取节点数和边数
n, m = map(int, input().split())
# 创建一个全0,大小为 n+1 行,n+1 列的邻接矩阵 graph
graph = [[0]*(n + 1) for _ in range(n + 1)]
# 循环 m 次,读取每条边的信息
for _ in range(m):
# 每次循环中读取起点和终点
s, t = map(int, input().split())
# 将邻接矩阵中对应起点和终点的元素设置为1
graph[s][t] = 1
# 创建一个列表存储结果
result = []
dfs(graph, 1, n, [1], result)
# 如果没有找到路径,返回-1
if not result:
print(-1)
else:
# 遍历 result 中每一个路径
for path in result:
# 将路径每个节点转换为字符串,并用空格连接
print(' '.join(map(str, path)))
if __name__ == "__main__":
main()
"""
邻接表写法
"""
from collections import defaultdict
# 收集符合条件的路径
result = []
# 1节点到终点的路径
path = []
# 1. 确定递归函数和参数
def dfs(graph, x, n):
# 2. 确定终止条件,当前遍历节点 x 为终点 n
if x == n:
result.append(path.copy())
return
# 3. 处理目前搜索节点出发的路径
# 找到 x指向的节点
for i in graph[x]:
# 遍历到的节点加入到路径中来
path.append(i)
# 进入下一层递归
dfs(graph, i, n)
# 回溯,撤销本节点
path.pop()
def main():
n, m = map(int, input().split())
# 邻接表
graph = defaultdict(list)
for _ in range(m):
s, t = map(int, input().split())
graph[s].append(t)
# 无论什么路径已经是从1节点出发
path.append(1)
# 开始遍历
dfs(graph, 1, n)
# 输出结果
if not result:
print(-1)
for pa in result:
print(' '.join(map(str, pa)))
if __name__ == "__main__":
main()
四、广搜理论基础(BFS)
使用场景:适合解决两点之间最短路径问题。
特点:源点开始,一圈一圈向外遍历,由近到远,由内而外。
队列实现广搜三部曲
1. 源点进队;
2. 队列不为空时,拿出队首元素;
3. 对队首元素进行扩展(遍历cur的邻接表),未被访问过的节点进队。
Note:保证队列中,距离单调递增。
"""
BFS模板
"""
# s表示第一个开始的节点
def BFS(graph, s):
queue = []
queue.append(s)
# 创建一个哈希表存储遍历过的节点
seen = set()
seen.add(s)
# 当队列不为空时
while (len(queue) > 0):
# 从队列中取出第一个节点
vertex = queue.pop(0)
# 找到vertex的邻接节点
nodes = graph[vertex]
# 遍历节点
for w in nodes:
# 如果这些邻接节点没有走过,将其添加到队列中
if w not in seen:
queue.append(w)
seen.add(w)
print(vertex)