紫书刷题进行中,题解系列【GitHub|CSDN】
例题6-10 UVA699 The Falling Leaves(23行AC代码)
题目大意
以树根节点为中心,画一根垂直线(可看成y轴),因此树根坐标为0,它的左子树根为-1,右子树根为+1,依次类推,即往左走-1,往右走+1,现在将坐标相同的点看成一叠,从左到右输出他们的权值和。
思路分析
和例题6-9有些类似,直观思路是想通过输入先序建树,然后再次dfs计算每叠的总和。
那么自然可利用同样的优化手段,即无需真正的建立一个二叉树,而是隐式建立二叉树(只遍历,不留下任何痕迹:),同时定义map<int,int> cnt;
来统计每叠对应的权值总和,因为map
对按键值从小到大排序,免去了输出时排序的繁琐,这也是为什么令左子树-1,右子树+1的缘故。
注意利用输入数据的先序特点,可使用递归建树,避免复杂的输入处理
注意点
- 每组测试用例输出均需跟上一个空行!!!
AC代码(C++11,先序隐式建树,map)
#include<bits/stdc++.h>
using namespace std;
map<int,int> cnt; // 位置->个数;统计每叠对应权值总和
void createTree(int pos=0) { // 先序隐式建树,同时累加每个位置的值
int v; scanf("%d", &v);
if (v != -1) {
cnt[pos] += v; // 累加值
createTree(pos-1); // 左子树
createTree(pos+1); // 右子树
}
}
int main() {
for (int i = 1; ; i ++) {
cnt.clear(); createTree(0); // 初始化,隐式建树求值
if (cnt.empty()) break; // 读到最后一个-1,结束
printf("Case %d:\n", i);
for (auto p : cnt) { // map按照key的字典序升序排列
printf("%d%s", p.second, p.first == cnt.rbegin()->first ? "\n" : " ");
}
puts(""); // 每个测试用例后均有空行
}
return 0;
}