Input
Copy
2 xA00tB00zC00D00 4 7 6 2 3 ab0C00D00 2 10 20
Output
Copy
34 40
二叉树的带权路径和APL等于叶子权值乘以根节点到叶子的分支数,然后求总和。
所以可以看出这道题需要求出每个叶子到根的高度就可以了,然后让权值与叶子到根的高度相乘。
求叶子节点到树高我们可以用dfs()
tips:千万不要给deep++,或者++deep,你就看这个地方,deep++了,假设递归左子树1->2,,那递归右子树的时候就是2->3了,因为你改变了,deep本身在这一层的时候
数组我存放的是按顺序存放的叶子节点,你们也可以用指针直接搞个结构体,然后到叶子的时候直接给叶子的高度赋值
这里我用前序找叶子,然后放入数组里。
tips:这里我为什么要用数组找叶子,明明结构体里面有权值和高度两个变量
1.本题输入特殊,虽然权值与叶子对应,但是是先全部输入完树的节点的,前序遍历建树。
2.如果不用数组存着叶子节点,我就需要构建到叶子的时候叶子输入权值,然后再找一次叶子高度计算和。
即使我们先dfs找高度,到叶子的时候输入叶子权值计算和,这样子可能用的不习惯
3.所以还是分4步走,构建树,权值输入,求高度(中间两个可交换位置),计算和。
代码如下:
#include <iostream>
#include <queue>
using namespace std;
struct nodtree
{
char value;///字符
nodtree* left, * right;//左子节点指针,右子节点指针
int length;///节点距离根节点的长度,就是高度
int quanzhi;///字符的权值,就是叶子节点的权值
nodtree()
{
left = NULL;
right = NULL;
}
nodtree(char ch)
{
value = ch;
left = NULL;
right = NULL;
}
};
queue<char>ss;///按顺序存取字符串然后依次取出字符
queue<nodtree*>p;用来构建树
//为什么喜欢用队列来当数组呢?
//个人习惯,因为你想想,我数组我需要指针tp++,但是我队列就每次取得都是第一个,然后把它pop就好了
//但是有个不好的就是这样子pop掉了,需要前面的数据就没了,看个人习惯和代码风格吧
nodtree* buildtree()
{
if (ss.empty())///首先判断有没有节点给我建树
{
return NULL;
}
if (ss.front() == '0')///如果是权值为0的节点那就是空节点,不需要建立
{
ss.pop();
return NULL;
}
nodtree* root;///这里就是常规建树了
root = new nodtree(ss.front());
ss.pop();
root->left = buildtree();
root->right = buildtree();
return root;
}
void before(nodtree* root)///本人习惯会写一个先序遍历检查树是否建的对
{
if (root == NULL)
{
return;
}
cout << root->value << " ";
before(root->left);
before(root->right);
}
vector<nodtree*>shuzu;
void qianxu(nodtree* root)///用前序遍历找叶子,因为节点也是前序遍历创建的,所以前序遍历找到的叶子跟字符串的叶子顺序是一样的
{
///例如字符串xA00tB00zC00D00
///可看出叶子是ABCD,所以前序遍历得到的叶子其实也是ABCD,顺序一样
/// 这里是我最开始题没看好导致的处理可能稍微复杂了一点
if (root == NULL)
{
return;
}
if (root->left == NULL && root->right == NULL)
{
shuzu.push_back(root);///这里是将叶子放进数组里
}
qianxu(root->left);
qianxu(root->right);
}
int index=0;///这个是用来控制数组下标的,从0开始,存的是叶子,第一个叶子,index=0,第二个叶子,index=1;
void dfs(nodtree* root, int deep)
{
if (root == NULL)///判断节点是不是空
{
return;
}
if (root->left == NULL && root->right == NULL)///判断是不是叶子节点
{
///我很喜欢这样子判断叶子,主要是觉得这样子能保证代码正确性,判断是不是叶子节点
shuzu[index]->length = deep;///叶子距离根的高度都存进数组里
index++;
}
dfs(root->left, deep + 1);///左递归左子树
dfs(root->right, deep + 1);///右递归右子树
}
int main()
{
int t;
cin >> t;
while (t--)
{
string ch;///输入字符串
cin >> ch;
int len = ch.length();///计算字符串长度
for (int i = 0; i < len; i++)
{
ss.push(ch[i]);///将字符串中的每个字符取出
}
nodtree* root;///设立根节点
root = buildtree();///建树
qianxu(root);///用前序遍历找一遍叶子,将叶子存入数组里,这里后面就不用处理别的节点了
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> shuzu[i]->quanzhi;///输入每个叶子的权值
}
dfs(root, 0);///用dfs找一次高度,计算每次叶子到树根的高度
int sum = 0;
for (int i = 0; i < n; i++)///每次遍历叶子节点,将叶子节点的高度✖权值然后加到sum里
{
sum += shuzu[i]->quanzhi * shuzu[i]->length;
}
cout << sum << endl;
index = 0;
}
return 0;
}