需要二刷
2021/2/21二刷,二刷题解已更新在最下面
来吐槽:
天哪我以前写的代码也太长了吧???不到40行一个DFS就写完的题目用了百来行?用的啥奇葩方法啊,看都看不懂。也太菜了吧???不过当初我还没学算法笔记,自己硬做的,现在看来也算是成长了吧。
第一次写的代码:
# include <iostream>
# include <vector>
# include <queue>
# include <map>
using namespace std;
/*
输入:
树的结点个数(N) 树中的非叶子结点个数(M)
M行:
非叶子结点的编号 非叶子结点的孩子的数量(K) 其K个孩子的编号
输出:
输出每一层的叶子结点的个数
*/
struct Node
{
int father;
bool haveChild; // 该结点是否有孩子
int level; // 结点所在树的哪一层
Node() = default;
Node(int f, bool h, int l):father(f), haveChild(h), level(l){}
};
struct Tree
{
vector<Node> nodes; // 存放结点的数组
int N; // 总结点个数
int M; // 非叶子结点个数
int depth; // 这棵树的层数(深度)
// 建立树的时候,以双亲表存储并计算出每一个节点所在层数和树的深度
Tree()
{
int ID; // 当前非叶子结点的ID(ID就是在nodes中的索引)
int K; // 当前非叶子结点的孩子个数
int ID_child; // 当前非叶子节点的孩子的ID
cin >> N;
if(N == 0)
return;
cin >> M;
nodes = vector<Node>(N+1, {-1, false, 0});
nodes[1].father = 0;
nodes[1].level = 1;
depth = nodes[1].level;
for(int i=0;i<M;++i){
cin >> ID >> K;
for(int j=0;j<K;++j){
cin >> ID_child;
nodes[ID].haveChild = (K != 0); // 如果孩子的数量大于0,设置为有孩子
nodes[ID_child].father = ID; // 设置子节点的父节点(一个孩子只有一个父亲)
/*当输入的顺序是乱的时候,每个节点所在的层数无法正确地算出!!导致depth也无法算出,所以要单独在下面弄个循环单独算出
nodes[ID_child].level = nodes[ID].level + 1; // 子节点的所在层数是父节点所在层数+1
depth = nodes[ID_child].level > depth ? nodes[ID_child].level : depth; // 更新最大层数
*/
}
}
// 单独算出每个结点的level和树的depth
int cnt = 1;
int j_baba;
while(cnt != 0)
{
cnt=0;
for(int j=1;j<=N;++j)
{
j_baba = nodes[j].father;
// 如果父节点已经有所在层数但是子节点没有所在层数,就对子节点进行所在层数进行设置
if(nodes[j_baba].level != 0 && nodes[j].level == 0){
nodes[j].level = nodes[j_baba].level + 1;
depth = nodes[j].level > depth ? nodes[j].level : depth; // 更新最大层数
}
// 如果父节点和子节点都没有所在层数
else
if(nodes[j_baba].level == 0 && nodes[j].level == 0)
cnt = 1;
}
}
}
void printEveryLevelChildNum()
{
map<int, int> mp;
// 广度优先遍历
queue<int> Q; // 建立一个队列存放结点的ID
Q.push(1); // 没有father的根节点先入队
while(!Q.empty())
{
// 根节点出队
int r = Q.front();
Q.pop();
// 访问根节点(如果当前节点有孩子,那么就让其所在层的叶子结点的数量+1)
if(!nodes[r].haveChild)
mp[nodes[r].level]++;
// 子节点入队(在双亲表中看哪个节点的父节点是当前节点r,是的话它就是子节点,就将其入队)
for(int i=1;i<=N;++i){
if(nodes[i].father == r){
Q.push(i);
}
}
}
// 输出每一层的叶子结点的数量(depth是最大层数)
for(int i=1;i<=depth;++i){
cout << mp[i];
if(i < depth)
cout << " ";
}cout << endl;
}
// 测试用,打印所有树节点的信息
void showTreeList(){
printf("ID father haveChild level\n");
for(int i=1;i<=N;++i){
printf("%d %d %d %d\n", i, nodes[i].father, nodes[i].haveChild, nodes[i].level);
}
}
};
int main()
{
Tree T;
// T.showTreeList();
T.printEveryLevelChildNum();
return 0;
}
/*
10 6
01 2 02 03
02 2 04 05
03 1 06
05 1 07
06 2 08 09
08 1 10
*/
二刷AC代码:
# include <bits/stdc++.h>
using namespace std;
int N, M;
vector<int> child[101];
map<int, int> leaf; // 层数:叶子结点数的映射
int maxlevel = -1;
void DFS(int u, int level){
if(child[u].size() == 0){
leaf[level]++;
maxlevel = max(maxlevel, level);
return;
}
for(int v: child[u])
DFS(v, level + 1);
}
int main(){
cin >> N >> M;
int u, K, v;
for(int i = 0;i < M;++i){ // 输入非叶子结点的孩子们
cin >> u >> K;
for(int j = 0;j < K;++j){
cin >> v;
child[u].push_back(v);
}
}
DFS(1, 0);
for(int i = 0;i <= maxlevel;++i)
cout << leaf[i] << (i == maxlevel ? "\n" : " ");
return 0;
}