总结自ACWing
1、树与图的存储(邻接表)
// N:节点数量
// M:边的数量
// i:节点的下标索引
// idx:边的下标索引
// h[N]:表示第i个节点的第一条边的idx
// e[M]:表示第idx条边的终点
// ne[M]:表示与第idx条边同起点的下一条边的idx
int h[N], e[M], ne[M], idx;
// 添加一条边a->b
void add(int a, int b) {
e[idx] = b; // 记录加入的边的终点节点
ne[idx] = h[a];
// h[a]表示节点a为起点的第一条边的下标,
// ne[idx] = h[a]表示把h[a]这条边接在了idx这条边的后面,其实也就是把a节点的整条链表接在了idx这条边后面;
// 目的是下一步把idx这条边当成a节点的单链表的第一条边,完成把最新的一条边插入到链表头的操作
h[a] = idx++; // a节点开头的第一条边置为当前边,idx移动到下一条边
}
// 初始化
idx = 0;
memset(h, -1, sizeof h);
2、树与图的遍历
2.1 深度优先搜索(DFS)
// 从节点u开始进行DFS
void dfs(int u) {
st[u] = true; // 表示u已经被访问过
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j])
dfs(j);
}
}
2.2 广度优先搜索(BFS)
// 从节点u开始进行BFS
void bfs(int u) {
queue<int> q;
st[u] = true; // 表示u已经被访问过
q.push(u);
while (q.size()) {
int t = q.front();
q.pop();
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j]) {
st[j] = true; // 表示j已经被访问过
q.push(j);
}
}
}
}