- 树是特殊结构的图,是一个无环连通图。
- 无向图可以转化为有向图(a <—> b => a -> b, b ->a )
- 有时候找只进不出的点为起点
- 稠密图用邻接矩阵( g[a][b] 表示 a -> b)
- 稀疏图用邻接表(数组模拟邻接表)
深度优先遍历模板:(使用邻接表)
dfs(int u){ // 使用邻接表
st[u] = true;
for(int i = h[u]; i!=-1; i = ne[i]){
int j = e[i];
if(!st[j])
dfs(j);
}
return;
}
数组模拟邻接表
h [ ] : 表头(n的元素有n的表头)
e [ ] : 存值
ne[ ] : 存下一个值的位置,相当于next()
idx:当前存储位置
初始化
所有头结点的next设为-1;
for(int i = 0;i<n;i++) h[i] = -1;
添加边 a -> b:
public static void add(int a,int b){
e[idx] = b; // idx当前位置装入值
ne[idx] = h[a]; // 头插法
h[a] = idx++;
}
题:
AcWing 846. 树的重心 - AcWing
给定一颗树,树中包含 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
import java.util.*;
class Main{
static final int N = 100010;
static int n,idx,ans = N;//将ans赋成最大的
static int[] e = new int[2*N];//单链表存储值
static int[] ne = new int[2*N];//单链表存储地址下标
static int[] h = new int[N];//存储每个结点,后接单链表,表示从该店出发距离为1的值
static boolean[] st = new boolean[N];//判断该点是否被搜索过
public static void main(String[] args){
Scanner in = new Scanner(System.in);
n = in.nextInt();
for(int i=0;i<N;i++)
h[i] = -1;//初值赋为一,表示下一节点为空
for(int i=0;i<n-1;i++){//创建图
int a = in.nextInt();
int b = in.nextInt();
add(a,b);
add(b,a);
}
dfs(1);//深度优先搜索
System.out.println(ans);
}
//dfs不直接返回答案,而是不断更新u对于的最大值的最小值
static int dfs(int u){
st[u] = true;//查询之后将该点删除
int sum = 1;//将该删除的点也加上,方便后面计算父结点的树的结点个数
int res = 0;//存储该结点的子树结点的最大值
for(int i=h[u];i!=-1;i=ne[i]){
int j = e[i];
if(st[j]!=true) {
int s = dfs(j);//获取子树的结点个数//对于每个结点,都会求其子树的节点个数
res = Math.max(res,s);//取不同子树的节点个数的最大值
sum += s;//加上子树结点个数
}
}
res = Math.max(res,n-sum);//取子树结点的最大与父节点的树的最大
ans = Math.min(res,ans);//取子树节点个数中最大值的最小值(对于m点,子树结点的最大值,对于整棵树,不同结点最大值中的最小值)
return sum;//返回的是子树的结点个数
}
static void add(int a,int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
}
使用BufferedReader快一半。