我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED
原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805424153280512
题目描述:
题目翻译:
1053 相等权重的路径
给定一棵非空树,其根节点为R,每个节点Ti都有一个相应的权重Wi。从R节点到叶子节点L的路径权重被定义为该路径上所有节点的Wi总和。
任给一棵权重树,你需要找出路径权重和给定数字相等的所有路径。举个例子,让我们考虑下图中的这棵树:对每一个节点,上方的数字是一个两位数的节点ID,而下方的数字是这个节点对应的权重。假设给定数字24,图中有4条不同的路径,其权重均是24:{10 5 2 7}, {10 4 10}, {10 3 3 6 2}和{10 3 3 6 2},在图中以红线标识出。
输入格式:
每个输入文件包含一个测试用例。在每个测试用例中,第一行有数0 < N <= 100,代表树中的节点总数,M(< N),代表非叶子节点数,以及0 < S < 2 ^ 30,代表给定的权重总值。接下来的一行包含N个正整数,分别表示Ti节点的权重值Wi(< 1000)。接下来的M行,每行都是以下格式:
ID K ID[1] ID[2] ... ID[K]
其中ID是一个两位数的数字,代表一个非叶子节点的编号,K是它的子节点总数,紧跟着的是一串子节点ID值。为简单起见,根结点ID值为00。
输出格式:
对每个测试用例,以非递增的顺序打印所有权重为S的路径。每一行输出从R到L的节点权重值。一行中所有的数字由一个空格分隔,行末不得有多余空格。
提示:如果对于i = 1, ⋯, k,其中1 <= k < min{n, m},均有Ai = Bi,且Ak+1 > Bk+1,则序列{A1,A2,⋯,An}被定义为比序列{B1,B2,⋯,Bm}要大。
输入样例:
20 9 24
10 2 4 3 5 10 2 18 9 7 2 2 1 3 12 1 8 6 2 2
00 4 01 02 03 04
02 1 05
04 2 06 07
03 3 11 12 13
06 1 09
07 2 08 10
16 1 15
13 3 14 16 17
17 2 18 19
输出样例:
10 5 2 7
10 4 10
10 3 3 6 2
10 3 3 6 2
知识点:树的深度优先遍历(回溯)
思路:树的深度优先遍历(回溯)
几个注意点:
(1)这是一棵普通性质的数,每个节点的孩子数都是不固定的,因此我们需要用一个结构体node存放节点的数据域和指针域。对于数据域,由两部分组成,分别是节点编号num和节点权值weight。对于指针域,我们使用静态写法,用一个vector<int>型的变量child来存放所有孩子节点的编号。
(2)最后的输出需要按权值从大到小排序,因此我们在读入时就事先对每个节点的子节点vector进行排序(即对vector中的节点按权值从大到小排序),这样在遍历时就会优先遍历到权值大的子节点。
(3)令vector<int>型的便来来保存路径。当枚举当前访问节点的子节点的过程中,就可以使用push_back()方法将子节点加入到路径中,然后往下一层递归,最后在下一层回溯上来之后将前面加入的子节点pop_back()即可。
(4)在深度优先遍历(回溯)的过程中,我们需要记录当前路径上的权值和sum。递归的过程如下:
a:首先把当前节点push_back()进path中
b:若sum > S,pop_back()后直接return。因为题给的节点权值都是正值,继续深度优先遍历得到的sum不可能和S相等,这是一次“剪枝”操作。
c:若sum == S,判断当前节点是否是叶子节点,如果是叶子节点则打印路径。无论是否是叶子节点,都需要pop_back()后直接return。
d:若sum < S,我们遍历当前访问节点的所有子节点,对每个子节点,进行递归调用。
e:最后别忘记需要pop_back()对path变量进行手动回溯操作。
(4)sort函数的自定义cmp函数只能用大于或者小于号,不能使用大于等于和小于等于,否则会报段错误。
时间复杂度和空间复杂度均是O(N)。
C++代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct node{
int weight;
vector<int> children;
};
int N, M, S, ID, K, child;
node Node[100];
vector<int> path;
bool cmp(int num1, int num2);
void dfs(int nowVisit, int sum);
int main(){
scanf("%d %d %d", &N, &M, &S);
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);
}
dfs(0, 0);
return 0;
}
bool cmp(int num1, int num2){
return Node[num1].weight > Node[num2].weight;
}
void dfs(int nowVisit, int sum){
path.push_back(nowVisit);
if(Node[nowVisit].children.size() == 0){
sum += Node[nowVisit].weight;
if(sum == S){
for(int i = 0; i < path.size(); i++){
printf("%d", Node[path[i]].weight);
if(i != path.size() - 1){
printf(" ");
}else{
printf("\n");
}
}
}
path.pop_back();
return;
}
if(sum > S){
return;
}
for(int i = 0; i < Node[nowVisit].children.size(); i++){
dfs(Node[nowVisit].children[i], sum + Node[nowVisit].weight);
}
path.pop_back();
}
C++解题报告: