PAT甲级刷题实录——1004

原题链接

https://pintia.cn/problem-sets/994805342720868352/problems/994805521431773184

思路

很明显这题需要用到树这个数据结构,问题是怎么来存。一开始我是这样想的:因为它只问了每一层叶子结点数,所以最简单的情况下我只需要两个数据就行,一个是结点的所在的层级,另一个是结点是否含有子结点。所有的结点都存储在vector中,另外创建一个存储每一层叶子结点个数的数组用于最后输出结果。遍历vector,记录每一层不含有子结点的个数,即为该层叶子结点个数,并把它存储到该层在结果数组中对应的位置上去。代码如下:

#include <iostream>
#include <vector>
using namespace std;
struct node
{
    int level;  //所在层级,从0开始
    bool hasChild = false;
};
int main()
{
    int nodeSum, nonLeafSum;    //结点总数,非叶子结点总数
    cin >> nodeSum >> nonLeafSum;
    vector<node> tree(nodeSum+1);   //树,从1开始计数
    tree[1].level = 0;  //初始化根节点所在的层级
    int maxLevel = 0;   //存储最大层数
    for (int i = 0; i < nonLeafSum; i++)
    {
        int parent;
        cin >> parent;
        tree[parent].hasChild = true;
        int childSum;
        cin >> childSum;
        for (int j = 0; j < childSum; j++)
        {
            int childNum;
            cin >> childNum;
            tree[childNum].level = tree[parent].level + 1;  //记录结点所在层级
            if (tree[childNum].level > maxLevel)
            {
                maxLevel = tree[childNum].level;    //更新最大层级
            }
        }
    }
    vector<int> result(maxLevel+1,0);   //存储输出结果,即每层的叶子节点数
    for (int i = 1; i <= nodeSum; i++)
    {
        if (tree[i].hasChild == false)
        {
            result[tree[i].level]++;
        }
    }
    for (int i = 0; i < maxLevel+1; i++)
    {
        if (i == 0)
            cout << result[i];
        else
            cout << ' ' << result[i];
    }
}

这段代码非常简洁,不到50行,乍一看看不出什么问题,于是我就输进评测系统测试了,但只是部分正确。但实在是看不出问题在哪,于是我只好上网查查别人的方法。

网上找的方法基本思路和我一样,但有一个地方做了一个更保险的做法,就是在确定每个结点的时,我是在第一遍读入数据的时候就开始确定的,而网上的方法则是读完数据以后重新遍历了一遍vector以确定每个结点的层级,为此需要在node结构体中加上每个结点的父结点信息。我觉得问题就是出在这。因为在一开始的时候我们只知道根节点所在层级。我的方法也是默认根节点是作为第一条数据读入的。但如果第一条读入的数据并不是根节点,那么后续的结点层级都会发生错误,因为子结点的层级是父结点的层级加1,而第一条读入的如果不是根节点的话我们就不知道父结点的层级。而网上的方法在读完其他数据以后根据父结点信息重新从第一个结点也就是根结点开始确定层级,这样就保证了后续结点的层级都能正确确定。我这样说可能不太清楚,我把借鉴了网上的思想之后重新修改的代码放在下面

代码

#include <iostream>
#include <vector>
using namespace std;
struct node
{
    int parent;
    int level;
    bool hasChild = false;
};
int main()
{
    int nodeSum, nonLeafSum;    //结点总数,非叶子结点总数
    cin >> nodeSum >> nonLeafSum;
    vector<node> tree(nodeSum+1);   //树,用双亲表示法
    tree[1].level = 0;
    tree[1].parent = -1;
    for (int i = 0; i < nonLeafSum; i++)
    {
        int parent;
        cin >> parent;
        tree[parent].hasChild = true;
        int childSum;
        cin >> childSum;
        for (int j = 0; j < childSum; j++)
        {
            int childNum;
            cin >> childNum;
            tree[childNum].parent = parent;
        }
    }
    int maxLevel = 0;   //存储最大层数
    for (int i = 1; i <= nodeSum; i++)
    {
        for (int j = 1; j <= nodeSum; j++)
        {
            if (tree[j].parent== i)
            {
                tree[j].level = tree[i].level + 1;
                if (tree[j].level > maxLevel)
                    maxLevel = tree[j].level;
            }
        }
    }
    vector<int> result(maxLevel+1,0);   //存储输出结果,即每层的叶子节点数
    for (int i = 1; i <= nodeSum; i++)
    {
        if (tree[i].hasChild == false)
        {
            result[tree[i].level]++;
        }
    }
    for (int i = 0; i < maxLevel+1; i++)
    {
        if (i == 0)
            cout << result[i];
        else
            cout << ' ' << result[i];
    }
}

补充知识——树的存储方法

通常有三种存储树的方法,分别是:1. 双亲表示法;2. 孩子表示法;3. 孩子兄弟表示法。关于各种表示方法的介绍在这篇博客中介绍得很详细:https://www.cnblogs.com/ssyfj/p/9459887.html

本题最适合采用的就是双亲表示法,因为所有的结点都存储在一个数组中,非常容易实现遍历以记录每一层的叶子结点数。但双亲表示法存在的问题就是很难遍历到一个结点的子结点。但本题中不需要遍历子结点。

原文地址:https://www.cnblogs.com/aopstudio/p/12180768.html

时间: 2024-10-30 08:40:07

PAT甲级刷题实录——1004的相关文章

PAT甲级刷题实录——1011

原题链接 https://pintia.cn/problem-sets/994805342720868352/problems/994805504927186944 思路 这题就很简单了,每行输入的时候找出最大的记录下来,同时记录下标.输入完毕后根据下标转换成结果(W,T,L)并储存起来,再根据每行的最大值计算profit.最后输出结果和profit即可,代码如下. 代码 #include <iostream> #include <vector> using namespace s

PAT甲级刷题实录——1010

原题链接 https://pintia.cn/problem-sets/994805342720868352/problems/994805507225665536 思路 这题是到目前为止比较难的一题,评测系统的通过率也只有 0.11. 首先需要理解基本题意.题目的要求是给一个已知进制的数,求能不能找出一个进制使得另一个未知进制的数在该进制下和已知进制的数数值相等.大部分人应该都会想到将两个数的数值都转换为十进制后做比较. 在理解了基本题意之后,做的过程中发现这题还有不少坑. 进制是没有上限的.

PAT甲级刷题实录——1013

原题链接 https://pintia.cn/problem-sets/994805342720868352/problems/994805500414115840 思路 题目大意是说一些城市之间有路相通,假设其中一个城市被敌方占领了,计算需要新修多少条路才能让剩下的城市全部联通.首先这是一个典型的图论问题,我们可以用邻接矩阵去存城市之间的联通关系.可以用深度遍历的思想去解决这个问题.思路大意如下:建立一个数组存储哪些城市已经被联通,1代表已联通,0代表未联通:定义一个变量记录需要新修的路的数量

PAT甲级刷题实录——1014

原题链接 https://pintia.cn/problem-sets/994805342720868352/problems/994805498207911936 思路 这题需要用到队列,而且不止一条.首先是每个等待窗口各需要一条,另外在黄线外的等待顾客需要一条.C++提供了现成了现成的队列类型,只要引用头文件queue即可. 算法基本运行过程是:在输入顾客等待时间时依次填满每条队列,超出队列容量的,即编号大于N*M+1的顾客,则push进黄线外的等待队列中.当有窗口有顾客处理完毕后,则将该顾

1085. Perfect Sequence (25)-PAT甲级真题

1085. Perfect Sequence (25) 时间限制 300 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CAO, Peng Given a sequence of positive integers and another positive integer p. The sequence is said to be a "perfect sequence" if M <= m * p where M and m

1020. Tree Traversals (25) PAT甲级真题

之前我看了这道题,实在是看不懂网上的解题答案,他们的具体思路基本上就是通过后续遍历和中序遍历,直接推出层次遍历. 我苦思冥想了半天,是在没看懂这种思路,于是想了一个笨点的但是也比较好理解的思路,通过后续和中序,先推出整个二叉树,再考虑 对二叉树层次遍历. 本题还有一点要注意的时在输出结果的末尾,如果使用了类似 pirntf("%d ",data); 这样的格式是不对的,一定要对末尾进行判断消除最尾端的空格. 首先最核心的部分是通过两次遍历反推回二叉树:这里的思路是,后续遍历的最末尾,一

1078. Hashing (25)-PAT甲级真题

1078. Hashing (25)The task of this problem is simple: insert a sequence of distinct positive integers into a hash table, and output the positions of the input numbers. The hash function is defined to be "H(key) = key % TSize" where TSize is the

PAT甲题题解-1111. Online Map (30)-PAT甲级真题(模板题,两次Dijkstra,同时记下最短路径)

题意:给了图,以及s和t,让你求s到t花费的最短路程.最短时间,以及输出对应的路径.   对于最短路程,如果路程一样,输出时间最少的. 对于最短时间,如果时间一样,输出节点数最少的.   如果最短路程和最短时间路径一样,合并输出一次即可. 纯粹就是练习dijkstra,没什么难的. 第一次dijkstra求最短路程,记录下每个节点的路程和时间. 第二次dijkstra求最短时间,记录下每个节点的时间和经过的节点数. pre数组用来存储前驱节点,保存路径 #include <iostream>

PAT甲级水题 A+B in Hogwarts(java string中分隔符的用法)

A+B in Hogwarts 在java.lang包中有String.split()方法,返回是一个数组 我在应用中用到一些,给大家总结一下,仅供大家参考: 1.如果用"."作为分隔的话,必须是如下写法,String.split("\\."),这样才能正确的分隔开,不能用String.split("."); 2.如果用"|"作为分隔的话,必须是如下写法,String.split("\\|"),这样才能正确