PAT甲级 树 相关题_C++题解

目录

  • 《算法笔记》重点摘要
  • 1004 Counting Leaves (30)
  • 1053 Path of Equal Weight (30)
  • 1079 Total Sales of Supply Chain (25)
  • 1090 Highest Price in Supply Chain (25)
  • 1094 The Largest Generation (25)
  • 1106 Lowest Price in Supply Chain (25)

《算法笔记》 9.2 树的遍历 重点摘要

1. 常考边界条件

  • 空树:没有结点
  • 树只有一个根节点时,它亦为叶子结点

2. 树的静态实现

(1) 定义
  • 需要数据域
struct Node{
    typename data;
    int level;
    vector<int> child;
} node[MAXN];
  • 不需要数据域,只需要树的结构
vector<int> child[MAXN];
(2) 新建结点
int index = 0;
int newNode (int value){
    node[index].data = value;
    node[index].child.clear();
    return index++;
}
(3) 先根遍历
void preorder (int root){
    printf("%d\n", node[root].data);
    for (int i = 0; i < node[root].child.size(); i++)
        preorder(node[root].child[i]);
}
(4) 层序遍历
void levelorder(int root){
    queue<int> q;
    q.push(root);
    node[root].level = 0;
    while(!q.empty()){
        int front = q.front();
        printf("%d ", node[front].data);
        q.pop();
        for (int i = 0; i < node[front].child.size(); i++){
            int child = node[front].child[i];
            node[child].level = node[front].level + 1;
            q.push(node[front].child[i]);
        }
    }
}

3. 树与搜索

  • 合法的 DFS 遍历过程即树的先根遍历过程
  • 合法的 BFS 遍历过程即树的层序遍历过程

1004 Counting Leaves (30)

题目思路:DFS

  • 记录当前节点的层级和树的深度,当层级高于深度时,更新树的深度
  • 若当前节点为叶结点,对应层级的叶节点数 ++
  • 若非叶结点,递归进入其子结点
  • 最后依据树的深度输出各层级叶结点数
#include<iostream>
#include<vector>
using namespace std;
vector<int> children[100];
int levelnum[100] = {0}, depth = 1;
void dfs(int index, int level)
{
	if (children[index].empty()){
		levelnum[level]++;
		if (level > depth) depth = level;
	}
	for (int i = 0; i < children[index].size(); i++)
		dfs(children[index][i], level+1);
}
int main()
{
	int n, m, id, k, child;
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++){
		scanf("%d%d", &id, &k);
		for (int j = 0; j < k; j++){
			scanf("%d", &child);
			children[id].push_back(child);
		}
	}
	dfs(1,1);
	printf("%d", levelnum[1]);
	for (int i = 2; i <= depth; i++)
		printf(" %d", levelnum[i]);
	return 0;
}

1053 Path of Equal Weight (30)

题目思路:DFS

  • 由于要按权值输出,每接收完一个节点的子结点后就对其子结点容器进行排序,这样保证 DFS 时直接输出就是从大到小的顺序
  • 记录路径用 vector,访问子结点 进入下一层递归 DFS 前将其 push_back,从递归返回时再 pop_back,继续压入这一层下一个子结点
  • sum == weights 时,要判断当前节点的子结点容器是否为空,即是否是叶结点,若不是直接 return
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int weights;
vector<int> path;
struct Node{
	int weight;
	vector<int> children;
} node[100];
bool cmp (int a, int b){ return node[a].weight > node[b].weight; }
void DFS(int index, int sumweight)
{
	if (sumweight > weights) return;
	if (sumweight == weights){
		if (!node[index].children.empty()) return;
		for (int i = 1; i < path.size(); i++)
			printf("%d ", node[path[i-1]].weight);
		printf("%d\n", node[path[path.size()-1]].weight);
		return;
	}
	for (int i = 0; i < node[index].children.size(); i++){
		int child = node[index].children[i];
		path.push_back(child);
		DFS(child, sumweight+node[child].weight);
		path.pop_back();
	}
}
int main()
{
	int n, m, id, k, child;
	scanf("%d%d%d", &n, &m, &weights);
	for (int i = 0; i < n; i++) scanf("%d", &node[i].weight);
	for (int i = 0; i < m; i++){
		scanf("%d%d", &id, &k);
		for (int j = 0; j < k; j++){
			scanf("%d", &child);
			node[id].children.push_back(child);
		}
		sort(node[id].children.begin(), node[id].children.end(), cmp);
	}
	path.push_back(0);
	DFS(0, node[0].weight);
	return 0;
}

1079 Total Sales of Supply Chain (25)

题目思路:DFS

  • 树结点没有数据域,只要保存供应和售出的子结点关系,用 vector 的数组保存子结点即可
  • 用 map 保存零售商 id 与对应的货品数量,不需要顺序用 unordered_map 即可
  • DFS 用参数 index 和 level 标记当前遍历的结点的下标和层数
  • 若遇到叶结点,即子结点容器为空时,从 map 中取出对应的货品数量,根据层数计算单价,计算此零售商销售额后加入 sum 值中
  • 遍历结束后 sum 保存所求值,按要求输出即可
#include<iostream>
#include<vector>
#include<unordered_map>
#include<cmath>
using namespace std;
vector<int> children[100000];
double sum = 0, price, rate;
unordered_map<int,int> retailer;
void DFS(int index, int level){
	if (children[index].empty())
		sum += price * pow(1 + rate/100, level-1) * retailer[index];
	for (int i = 0; i < children[index].size(); i++)
		DFS(children[index][i], level+1);
}
int main()
{
	int n, k, id, amount;
	scanf("%d%lf%lf", &n, &price, &rate);
	for (int i = 0; i < n; i++){
		scanf("%d", &k);
		if (!k) scanf("%d", &retailer[i]);
		for (int j = 0; j < k; j++){
			scanf("%d", &id);
			children[i].push_back(id);
		}
	}
	DFS(0,1);
	printf("%.1f", sum);
	return 0;
}

1090 Highest Price in Supply Chain (25)

题目思路

  • 树结点没有数据域,只要保存供应和售出的子结点关系,用 vector 的数组保存子结点即可
  • DFS 求树的最大深度和叶结点个数,按要求计算并输出
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
vector<int> children[100000];
int depth = 1, leafnum = 0;
void DFS(int index, int level){
	if (level > depth){
		depth = level;
		leafnum = 1;
	}
	else if (level == depth) leafnum++;
	for (int i = 0; i < children[index].size(); i++)
		DFS(children[index][i], level+1);
}
int main()
{
	int n, supplier, root;
	double price, rate;
	scanf("%d%lf%lf", &n, &price, &rate);
	for (int i = 0; i < n; i++){
		scanf("%d", &supplier);
		if (supplier == -1) root = i;
		else children[supplier].push_back(i);
	}
	DFS(root,1);
	printf("%.2f %d\n", price * pow(1 + rate/100, depth-1), leafnum);	
	return 0;
}

1094 The Largest Generation (25)

BFS(层序遍历)

  • 要记录每层对应的结点数,在结点中设 level 变量记录层数,用 vector 记录子结点的下标
  • 层序遍历,每层将子结点压入队列时为子结点赋 level 值,弹出队列时给 level 值对应的数量 ++
  • 最后遍历记录每层结点数的 map,找到结点数最多的层输出
#include<iostream>
#include<unordered_map>
#include<queue>
using namespace std;
struct Node{
	int level;
	vector<int> children;
} node[100];
int main()
{
	int n, m, id, k, child, root = 1, maxnum = 1, maxlevel = 1;
	scanf("%d%d",&n,&m);
	for (int i = 0; i < m; i++){
		scanf("%d%d", &id, &k);
		for (int j = 0; j < k; j++){
			scanf("%d", &child);
			node[id].children.push_back(child);
		}
	}
	unordered_map<int,int> levelnum;
	queue<int> q;
	q.push(root);
	node[root].level = 1;
	while (!q.empty()){
		int now = q.front();
		levelnum[node[now].level]++;
		q.pop();
		for (int i = 0; i < node[now].children.size(); i++){
			int child = node[now].children[i];
			q.push(child);
			node[child].level = node[now].level + 1;
		}
	}
	for (auto it: levelnum){
		if (it.second > maxnum){
			maxnum = it.second;
			maxlevel = it.first;
		}
	}
	printf("%d %d\n", maxnum, maxlevel);
	return 0;
} 

DFS

  • 用参数 index 和 level 标记当前遍历的结点的下标和层数
  • 数组 levelnum 标记当前层数 level 所含结点数
  • 最后遍历一遍 levelnum 数组找出最大值。
#include<iostream>
#include<vector>
using namespace std;
vector<int> children[100];
int levelnum[100] = {0};
void dfs(int index, int level){
	levelnum[level]++;
	for (int i = 0; i < children[index].size(); i++)
		dfs(children[index][i], level+1);
}
int main()
{
	int n, m, id, k, child, maxnum = 1, maxlevel = 1;
	scanf("%d%d",&n,&m);
	for (int i = 0; i < m; i++){
		scanf("%d%d", &id, &k);
		for (int j = 0; j < k; j++){
			scanf("%d", &child);
			children[id].push_back(child);
		}
	}
	dfs(1,1);
	for (int i = 1; i < 100; i++){
		if (levelnum[i] > maxnum){
			maxnum = levelnum[i];
			maxlevel = i;
		}
	}
	printf("%d %d\n", maxnum, maxlevel);
	return 0;
} 

1106 Lowest Price in Supply Chain (25)

题目思路:DFS

  • 保存最小叶结点的深度 depth,对应深度的叶结点个数 leafnum
  • DFS 遇到叶结点与 depth 比较,若相等将个数 ++,若小于 depth 说明找到了更小的深度,更新 depth,重置 leafnum = 1
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
vector<int> children[100000];
int depth = 100000;
int leafnum = 0;
void DFS(int index, int level)
{
	if (children[index].empty()){
		if (level == depth) leafnum++;
		else if (level < depth){
			depth = level;
			leafnum = 1;
		}
	}
	for (int i = 0; i < children[index].size(); i++)
		DFS(children[index][i], level+1);
}
int main()
{
	int n, k, child;
	double price, rate;
	scanf("%d%lf%lf", &n, &price, &rate);
	for (int i = 0; i < n; i++){
		scanf("%d", &k);
		for (int j = 0; j < k; j++){
			scanf("%d", &child);
			children[i].push_back(child);
		}
	}
	DFS(0,1);
	printf("%.4f %d", price * pow(1 + rate/100, depth-1), leafnum);
	return 0;
}
posted @ 2019-08-29 23:27  鲸90830  阅读(412)  评论(0编辑  收藏  举报