算法day43-图论(1)
目录
- 理论基础
- 深搜理论基础
- 所有可达路径
- 广搜理论基础
一、理论基础
1. 图的种类
有向图、无向图、权值
2. 度
度【无向图】:有多少条边
出度、入度【有向图】:箭头指出去、箭头指回来
3. 连通性
连通图【无向图】:图里面任何一个节点可以到达其他所有节点
强连通图:【有向图】:图里面任何一个节点可以到达其他所有节点
连通分量【无向图】:极大连通子图,一个子图里面任何一个节点可以到达任何其他节点
强连通分量【有向图】
4. 图的构造(很重要!!)
朴素存储:二维数组,一一对应,把每条边两个节点记录下来
邻接矩阵:二维数组,有相连的就标记为1(缺点是当节点数较多时,占用内存空间)
邻接表:数组+链表(适合节点很多,边很少)
5. 图的遍历
DFS、BFS
二、深搜理论基础
深搜的概念、流程。
深搜的伪代码。
三、所有可达路径

方法一:邻接矩阵存储
import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class Main { static List<List<Integer>> result = new ArrayList<>(); // 收集符合条件的路径 static List<Integer> path = new ArrayList<>(); // 1节点到终点的路径 public static void dfs(int[][] graph, int x, int n) { // 当前遍历的节点x 到达节点n if (x == n) { // 找到符合条件的一条路径 result.add(new ArrayList<>(path)); return; } for (int i = 1; i <= n; i++) { // 遍历节点x链接的所有节点 if (graph[x][i] == 1) { // 找到 x链接的节点 path.add(i); // 遍历到的节点加入到路径中来 dfs(graph, i, n); // 进入下一层递归 path.remove(path.size() - 1); // 回溯,撤销本节点 } } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int m = scanner.nextInt(); // 节点编号从1到n,所以申请 n+1 这么大的数组 int[][] graph = new int[n + 1][n + 1]; for (int i = 0; i < m; i++) { int s = scanner.nextInt(); int t = scanner.nextInt(); // 使用邻接矩阵表示无向图,1 表示 s 与 t 是相连的 graph[s][t] = 1; } path.add(1); // 无论什么路径已经是从1节点出发 dfs(graph, 1, n); // 开始遍历 // 输出结果 if (result.isEmpty()) System.out.println(-1); for (List<Integer> pa : result) { for (int i = 0; i < pa.size() - 1; i++) { System.out.print(pa.get(i) + " "); } System.out.println(pa.get(pa.size() - 1)); } } }
方法二:邻接表存储
import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Scanner; public class Main { static List<List<Integer>> result = new ArrayList<>(); // 收集符合条件的路径 static List<Integer> path = new ArrayList<>(); // 1节点到终点的路径 public static void dfs(List<LinkedList<Integer>> graph, int x, int n) { if (x == n) { // 找到符合条件的一条路径 result.add(new ArrayList<>(path)); return; } for (int i : graph.get(x)) { // 找到 x指向的节点 path.add(i); // 遍历到的节点加入到路径中来 dfs(graph, i, n); // 进入下一层递归 path.remove(path.size() - 1); // 回溯,撤销本节点 } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int m = scanner.nextInt(); // 节点编号从1到n,所以申请 n+1 这么大的数组 List<LinkedList<Integer>> graph = new ArrayList<>(n + 1); for (int i = 0; i <= n; i++) { graph.add(new LinkedList<>()); } while (m-- > 0) { int s = scanner.nextInt(); int t = scanner.nextInt(); // 使用邻接表表示 s -> t 是相连的 graph.get(s).add(t); } path.add(1); // 无论什么路径已经是从1节点出发 dfs(graph, 1, n); // 开始遍历 // 输出结果 if (result.isEmpty()) System.out.println(-1); for (List<Integer> pa : result) { for (int i = 0; i < pa.size() - 1; i++) { System.out.print(pa.get(i) + " "); } System.out.println(pa.get(pa.size() - 1)); } } }
四、广搜理论基础
1. 广搜的概念
广度优先搜索(Breadth-First Search,简称 BFS)是一种图的遍历算法,从起点开始,一层一层地向外扩展搜索,直到遍历完所有可以到达的节点。
它的本质是使用队列(Queue)来保证节点的访问顺序:先进先出,每次从队首取出一个节点,将它未访问的邻接节点加入队尾。
BFS 常用于:
-
求最短路径(单位边权情况下)
-
判断连通性、层次结构
-
拓扑排序等问题
2. 广搜的特点
-
按“距离起点的远近”逐层扩展
-
通常需要配合一个
visited[]数组,防止重复访问 -
对于无权图最短路径问题非常高效
-
可用于搜索所有从起点出发的最短可达路径
3. BFS 的伪代码框架
函数 BFS(图 g, 起点 s): 创建队列 queue,初始加入起点 s 标记 s 为已访问 当队列不为空: 当前节点 cur = 队首元素出队 对于 cur 的每个相邻节点 next: 如果 next 未被访问: 将 next 入队 标记 next 为已访问
4. Java 中 BFS 的实现要点
-
使用
Queue<Integer>作为主队列结构(推荐LinkedList实现) -
图的存储结构通常使用邻接表
List<List<Integer>>或邻接矩阵int[][] -
搭配一个布尔数组
visited[]或整数数组dist[]来记录访问状态或层数
浙公网安备 33010602011771号