1、题目大意
- 题目链接UVa 297
- 给出结点值为 p, e, f 的两个严格四叉树(非叶结点的度为 4)的先序遍历序列,p 代表灰色,e 代表白色,f 代表黑色,将两个树对应的结点颜色相融合,求最终黑结点代表的像素个数。其中根结点代表像素数为1024个,其余每个结点代表的像素数为上一层结点的四分之一。
2、解题思路
- 根据先序序列就可以确定这个四叉树。因为本题中,严格四叉树的结点个数为 4n+1 个,如果结点值为 p,则该结点有子树;如果结点值为 e 或 f ,则该结点没有子树。
- 根据两个先序序列分别递归建树 tree1 和 tree2。
- 根据规则合并两个树,合并的结果存到 tree1 中。
- 遍历树 tree1 ,统计黑色结点代表的像素的个数。
3、参考代码
#include<iostream>
#include<string>
using namespace std;
struct node {
char color;
node *n1, *n2, *n3, *n4;
node() :color('e'), n1(NULL), n2(NULL), n3(NULL), n4(NULL) {}
};
node* build(string& s, int& pos) {
node* root = new node();
root->color = s[pos];
if (s[pos] == 'p') {
pos++; root->n1 = build(s, pos); pos++; root->n2 = build(s, pos);
pos++; root->n3 = build(s, pos); pos++; root->n4 = build(s, pos);
}
return root;
}
void merge(node* tree1, node* tree2) {
if (tree2->color == 'f') {
tree1->color = 'f';
tree1->n1 = tree1->n2 = tree1->n3 = tree1->n4 = NULL;
}
else if (tree2->color == 'p' && tree1->color != 'f') {
if (tree1->color == 'e') {
tree1->n1 = tree2->n1; tree1->n2 = tree2->n2;
tree1->n3 = tree2->n3; tree1->n4 = tree2->n4;
}
tree1->color = 'p';
merge(tree1->n1, tree2->n1); merge(tree1->n2, tree2->n2);
merge(tree1->n3, tree2->n3); merge(tree1->n4, tree2->n4);
}
}
int cnt(node* tree, int level) {
int sum = 0;
if (tree == NULL) return 0;
if (tree->color == 'f')
sum += 1024 / level;
sum += cnt(tree->n1, level * 4);
sum += cnt(tree->n2, level * 4);
sum += cnt(tree->n3, level * 4);
sum += cnt(tree->n4, level * 4);
return sum;
}
int main() {
int n;
cin >> n;
while (n--) {
string s;
cin >> s;
int pos = 0;
node* tree1 = build(s, pos);
cin >> s;
pos = 0;
node* tree2 = build(s, pos);
merge(tree1, tree2);
cout << "There are " << cnt(tree1, 1) << " black pixels." << endl;
}
return 0;
}
刘大爷书上的代码:
//刘大爷思路,直接模拟画出这个 32*32 的黑白图像的过程,边画边统计黑色结点的个数。
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int cnt;
int pic[32][32];
//把字符串“画”到 以(r, c)为左上顶点,宽度为 w 的图像 pic 中。
void draw(string& s, int& pos, int r, int c, int w) {
if (s[pos] == 'p') {
draw(s, ++pos, r + w / 2, c , w / 2);
draw(s, ++pos, r + w / 2, c + w / 2, w / 2);
draw(s, ++pos, r , c , w / 2);
draw(s, ++pos, r , c + w / 2, w / 2);
}
else if (s[pos] == 'f') {
for (int i = r; i < r + w; i++)
for (int j = c; j < c + w; j++)
if (pic[i][j] == 0) {
pic[i][j] = 1;
cnt++;
}
}
}
int main() {
int n;
cin >> n;
while (n--) {
memset(pic, 0, sizeof(pic));
cnt = 0;
string s;
int pos = 0;
cin >> s;
draw(s, pos, 0, 0, 32);
pos = 0; cin >> s;
draw(s, pos, 0, 0, 32);
cout << "There are " << cnt << " black pixels." << endl;
}
return 0;
}
4、解题感悟
- 刘大爷这个思路太妙了!直接模拟画出这个图像的过程,同时统计黑色像素的数目。思路很清晰,代码也很简单。
- 思考问题产生的过程,设置合理的数据结构,然后去模拟这个过程,进而解决这个问题。这可能就是所谓的面向对象编程思想吧。
- 多思考,多总结。