文章目录
- 例题
- 846. 树的重心(深度优先遍历 / 树形DP)⭐⭐⭐⭐⭐🚹🚹🚹🚹🚹(重要!好题!)
- 847. 图中点的层次
- 相关链接
要学会建树、建图的通用方法。
dfs 和 bfs 的代码框架。
例题
846. 树的重心(深度优先遍历 / 树形DP)⭐⭐⭐⭐⭐🚹🚹🚹🚹🚹(重要!好题!)
https://www.acwing.com/problem/content/848/
在 dfs 的过程中,统计各个节点作为断点时的连通块最大值。
import java.util.*;
public class Main {
static List<Integer>[] g;
static int ans = Integer.MAX_VALUE, n = 0;
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
g = new ArrayList[n + 1];
Arrays.setAll(g, e -> new ArrayList<Integer>());
for (int i = 0; i < n - 1; ++i) {
int a = scanner.nextInt(), b = scanner.nextInt();
g[a].add(b);
g[b].add(a);
}
dfs(1, 0); // 为什么要用dfs?因为dfs可以求出子树的大小
System.out.println(ans);
}
static int dfs(int x, int fa) {
// res记录删除该节点之后各个连通块中点数的最大值;sum记录该节点为根节点时所在连通块点的数量
int res = 0, sum = 1;
for (int y: g[x]) {
if (y != fa) {
int s = dfs(y, x); // 枚举各个x的子节点y作为根节点时的连通块大小
res = Math.max(res, s);
sum += s;
}
}
res = Math.max(res, n - sum); // n - sum 是 x 的父节点以上的那个连通块的大小
ans = Math.min(ans, res);
return sum;
}
}
847. 图中点的层次
https://www.acwing.com/problem/content/849/
看到最短距离就可以想到使用宽搜。
注意!
:题目中说明了 a 和 b 表示存在一条从 a 走到 b 的边,即这是一个有向图。在建图的过程中,对于每一行只需要添加一条路径就可以了。
import java.util.*;
public class Main {
static List<Integer>[] g;
static int n, m;
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
m = scanner.nextInt();
g = new ArrayList[n + 1];
Arrays.setAll(g, e -> new ArrayList<Integer>());
for (int i = 0; i < m; ++i) {
int a = scanner.nextInt(), b = scanner.nextInt();
g[a].add(b); // 只需要添加从 a 走到 b 的路径
}
System.out.println(bfs());
}
static int bfs() {
Queue<Integer> q = new LinkedList<>();
boolean[] st = new boolean[n + 1];
q.offer(1);
st[1] = true;
int ans = 0;
while (!q.isEmpty()) {
int sz = q.size();
for (int i = 0; i < sz; ++i) {
int x = q.poll();
if (x == n) return ans;
for (int y: g[x]) {
if (!st[y]) {
st[y] = true;
q.offer(y);
}
}
}
++ans;
}
return -1;
}
}
相关链接
更多关于树形 DP 可见:
【算法】树形DP ①(树的直径)
【算法】树形DP ② 打家劫舍Ⅲ(树上最大独立集)
【算法】换根DP