• PAT 甲级测试题目 -- 1004 Counting Leaves


    题目链接

    题目大意:

    家谱图通常使用家谱树表示(顾名思义,使用树的形式表示),求出家谱图中每一层中叶节点的数量

    输入

    每个测试用例包含以下输入数据:
      第一行输入两个数据,一个是树的总结点数 N,范围为 0<N<100;一个是非叶节点的个数 M,范围为 M < N。
      接下来的 M 行输入每个非叶节点的 节点号,所含有的节点,以及所含有的每个节点号

    输出

      输出每一层的叶节点个数,各个层数叶节点个数之间用空格隔开,行末没有空格

    输入用例:
    2 1
    01 1 02
    输出用例:
    0 1

    此题较为简单,并且没有坑点,因此理顺思路便可以AC

    分析

      从题中给出的信息可以知道,本题实际上是求出树中每一层节点的叶节点,也就是不含有子节点的节点。

      先不考虑如何计算,先考虑如何存储。

      观察输入用例,发现输入数据中的个位数字均使用 0x (x表示小于10的正整数)的形式表示,因此我们需要用字符串来接受这样的输入,并且将其转换为整数,方便处理。

      为了方便对树操作,我在代码中定义了一个二维数组用于存储这个家谱树,输入数据前将其中的每个元素初始化为 0。二维数组中的 [N][0] 元素设置为该层的节点数,[N][1] 至 [N][M] 为该层所有的节点号。

      由于上述每层中各个节点之间关系不如父子节点的关系那么容易寻找,因此我起初觉得最好的办法是将每层中的节点关联起来。但是如果想要将每层之间的节点关联起来,最好的策略就是定义一个二维数组,使用深度优先遍历将每层的节点号放进二维数组,对应的层数就是二维数组中 [N][M] 中的 N,节点则是 M。

      但是这个过程实际上已经将每层的叶节点遍历了一遍,因此我想,干脆用这种方法直接统计每层叶结点的数量,也就是统计家谱树二维数组中 [M][0] 为 0 的元素。

      由于需要标识层数,因此递归实现深度优先遍历的方法中,需要一个标识层数的变量。

      由于要统计每层的叶节点数,因此需要一个一维数组存储叶节点数,层数对应下标[Layer],每层的叶节点数对应下标对应的值(value) Array[Layer] = value

    实现

    以下是代码

    #include<iostream>
    #include<string>
    #include<string.h>
    using namespace std;
    // 定义最大节点数,给定100位是为了留出一位存储节点的子节点数量
    #define N 100
    // 定义最大非叶节点数
    #define M 98
    // 储存答案	
    int AnswerList[99];
    // 确定层数
    int Layer = 0;
    
    
    // 针对本题两位数设置字符串转数字函数,用户处理第2~N行输入
    int StrToNum(string NumText) {
    	return ((int)(NumText[0] - '0') * 10) + ((int)(NumText[1] - '0'));
    }
    // 计算答案,保存在AnswerList中
    void CreateList(int family[100][100], int layer, int node_index) {
    	if (Layer < layer)
    		Layer = layer;
    	if (family[node_index][0] == 0) {
    		// 查看当前的节点以及节点所在的层数
    		// cout << "node_index = " << node_index << "  layer = " << layer << endl;
    		AnswerList[layer]++;
    		return;
    	}
    	else {		
    		for (int i = 1; i <= family[node_index][0]; i++) 
    			CreateList(family, layer + 1, family[node_index][i]);		
    
    	}
    
    }
    
    int main() {
    	// 定义 总节点,非叶节点
    	int nodes, non_leaf_nodes;
    	// 定义存储家谱的数组,包括各层节点以及各个节点包含的子节点
    	int family[N][N];	
    
    	// 将数组清零,方便之后的计数
    	/*
    	(由于录入数据的时候,不含有子节点的节点是不输入数据的,
    	因此不做初始化则数组中为脏值,或者判断其是否大于零,这里保险起见给定初始值 0)
    	*/
    	memset(family, 0, sizeof(family));
    
    	// 初始化第一行输入数据
    	cin >> nodes >> non_leaf_nodes;
    	// 初始化各个节点的输入信息
    	for (int i = 0; i < non_leaf_nodes; i++) {
    		// 定义变量接收输入的节点
    		string StrIndex = "";		
    		cin >> StrIndex;
    		// 将节点转成 int 类型的数据
    		int Index = StrToNum(StrIndex);
    		// 记录该节点的叶子节点的数量
    		cin >> family[Index][0];
    		// 循环记录该节点下面所有的叶子节点,用于检索输出
    		for (int j = 1; j <= family[Index][0]; j++) {
    			// 记录输入的子节点数据
    			string TempIndex;
    			int tempindex;
    			cin >> TempIndex;
    			tempindex = StrToNum(TempIndex);
    			// 将输入的数据存入数组,用于后期计算各层节点数
    			family[Index][j] = tempindex;
    		}
    	}
    
    	// 测试输入数据是否存储正确
    	//cout << "********************" << endl;
    	//for (int i = 1; i <= non_leaf_nodes; i++) {
    	//	for (int j = 0; j <= family[i][0]; j++) {
    	//		cout << family[i][j] << " ";
    	//	}
    	//	cout << endl;
    	//}	
    	//cout << "********************" << endl;
    	//
    	// 初始化答案
    	memset(AnswerList, 0, sizeof(AnswerList));
    	CreateList(family, 0, 1);
    	
    
    	for (int i = 0; i <= Layer; i++) {
    		cout << AnswerList[i];
    		if (i != Layer) {
    			cout << " ";
    		}
    	}
    
    	return 0;
    }
    

    测试数据:

    输入:
    15 9
    01 2 02 03
    02 3 04 05 06
    03 2 07 08
    05 2 09 10
    07 1 12
    08 1 13
    09 1 11
    11 1 14
    13 1 15

    输出:
    0 0 2 2 1 1

    希望能够对你有所帮助!

  • 相关阅读:
    New Skateboard
    1127
    一张图看懂开源许可协议,开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别
    vim 快捷键绑定
    使用git 上传项目到gitee/github
    Linux进程/线程调度策略与 进程优先级
    【框架】共享内存组设计思路与实现(更新中)
    linux下六大IPC机制【转】
    详解Linux内核红黑树算法的实现
    Linux 内核里的数据结构:红黑树(rb-tree)
  • 原文地址:https://www.cnblogs.com/Breathmint/p/10270502.html
Copyright © 2020-2023  润新知