涉及知识点
1.静态链表在树中的意义
1).h[u];
代表的是以u为双亲的孩子在链表中的下标。
这也是为什么h要初始化成-1,因为没有任何孩子的情况下,下标是-1。当有一个孩子,存在0,
以此类推,维护的是一个顺序表的结构。
2).e[h[u]],ne[h[u]]:
由于h存的是链表的下标,e[下标]存的就是链表中的value了。
ne[下标]是一个指针,存的是下一个结点的地址。
因此e[],ne[]的索引结构都是用h[]来驱动的,只不过e[]寻找的是值;
而ne[]==-1时说明到达了表尾。
3).多个孩子怎么办:
如1)所述,实际上同一层所有的孩子作为兄弟,转在同一个链表中,当然可以很容易通过双亲
轻松遍历所有的孩子。
2.递归访问树
1).分类
这棵树,对于每一层孩子数量这个问题来说,分两类:
叶子结点;非叶节点
2).处理
针对叶子结点,显然是返回点。此时可以更新叶子节点数量,也可以更新最大层数。
针对非叶结点,利用链表性质,以此结点为双亲,递归访问所有孩子。利用了1.3)里面所说的方法。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=110;
int e[N],ne[N],h[N],idx;
int dep[N],max_dep;
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int depth){
if(h[u]==-1){
dep[depth]++;
max_dep=max(max_dep,depth);
return;
}
for(int i=h[u];~i;i=ne[i]){
dfs(e[i],depth+1);
}
}
int main(){
int n,k;
cin>>n>>k;
memset(h,-1,sizeof h);
for(int i=0;i<k;i++){
int id,m;
cin>>id>>m;
while(m--){
int son;
cin>>son;
add(id,son);
}
}
dfs(1,0);
cout<<dep[0];
for(int i=1;i<=max_dep;i++){
cout<<" "<<dep[i];
}
puts("");
return 0;
}