PAT-ADVANCED1053——Path of Equal Weight

版权声明:我的GitHub:https://github.com/617076674。真诚求星! https://blog.csdn.net/qq_41231926/article/details/83575634

我的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},均有A​i​​ = B​i​​,且A​k+1​​ > B​k+1​​,则序列{A​1​​,A​2​​,⋯,A​n​​}被定义为比序列{B​1​​,B​2​​,⋯,B​m​​}要大。

输入样例:

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 num;
	int weight;
	vector<int> child;
};

int N;	//节点个数 
int M;	//非叶子节点个数 
int S;	//路径权值 
node Node[100];	//建立一个大小为结点上限个数的node型数组
vector<int> path;	//存放路径 

bool cmp(int a, int b);
void dfs(int nowVisit, int sum); 
void printPath();

int main(){
	cin >> N >> M >> S;
	for(int i = 0; i < N; i++){
		cin >> Node[i].weight;
	}
	int ID, K, childID;
	for(int i = 0; i < M; i++){
		cin >> ID >> K;
		for(int j = 0; j < K; j++){
			cin >> childID;
			Node[ID].child.push_back(childID);
		}
		sort(Node[ID].child.begin(), Node[ID].child.end(), cmp);	//对每个节点的子节点进行排序 
	}
	dfs(0, 0);	//从0节点开始深度优先遍历 
	return 0;
}

bool cmp(int a, int b){
	return Node[a].weight > Node[b].weight;	//用大于等于号会出现段错误 
}

void dfs(int nowVisit, int sum){
	path.push_back(nowVisit);
	if(sum + Node[nowVisit].weight > S){
		path.pop_back();
		return;
	}
	if(sum + Node[nowVisit].weight == S){
		if(Node[nowVisit].child.size() == 0){	//判断当前节点是否是叶子节点 
			printPath();
		}
		path.pop_back();
		return;
	}
	for(int i = 0; i < Node[nowVisit].child.size(); i++){
		dfs(Node[nowVisit].child[i], sum + Node[nowVisit].weight);
	}
	path.pop_back();
}

void printPath(){
	for(int i = 0; i < path.size(); i++){
		cout << Node[path[i]].weight;
		if(i != path.size() - 1){
			cout << " ";
		}
	}
	cout << endl;
}

C++解题报告:

猜你喜欢

转载自blog.csdn.net/qq_41231926/article/details/83575634