题意:
落叶成堆, 一颗二叉树, 每个节点包含一定的叶子数, 上面的每个节点都会落下, 如果他们的垂直位置相同, 就会落成同一堆(叶子数叠加), 当所有节点掉落完后, 输出从左到右所有堆中的叶子个数.
(1). 对于每一个节点, 它的左子树根节点在它的左边一个单位处, 它的右子树根节点在它的右边一个单位处;
(2). 按树的前序遍历进行输入, 如果是 -1, 表示节点为空.
思路:
使用一个 vector 来存放所有的堆, 堆的起始位置从 vector 中间开始;
1. 使用一个栈来存放待处理的节点(左/右子树不为空), 每读入一个数, 就看当前栈顶的元素的左/右指针是否为空(先左后右):
(1). 若左指针为空, vector 上当前堆的 index 左移一位, 并置左指针不为空;
(2). 若右指针为空, vector 上当前堆的 index 右移一位, 并置右指针不为空.
2. 若左右指针皆不为空, 说明当前元素操作完毕, 栈顶元素应当出栈.
3. 对于读入的每个正数, 经上面步骤确定堆的 index 后, 就把当前读入的数加到这个堆的 index 对应的数上.
4. 对于正数, 以上操作完成后, 需要入栈; 对于 -1, 则无须入栈.
5. 所有操作完成后, 如果此时栈为空, 说明读入完毕.
要点:
不要看到树就想建树, 看能不能在线性的数据结构中把树的要点给模拟出来, 这样可以简化解法.
题目:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=104&page=show_problem&problem=640
代码:
# include <iostream> # include <string> # include <cstdio> # include <cstring> # include <vector> # include <cctype> # include <assert.h> # include <list> using namespace std; // 树叶掉落, 聚成堆, 要求每一堆的叶子数 // 全部节点都会落下来 // 输入按树的前序遍历 // 碰到正数就往左走, 每读入一个数, 都依次填充左右空指针, // 直到没有空指针可填, 且下一个数是负数为止 // 最大堆数 const int NUM_PILE = 80; vector<int> PILES(NUM_PILE, 0); // index 表示当前节点在 pile 中的下标 // left, right 表示其左.右节点是否已处理完毕 class Node { public: Node (int index, bool left = false, bool right = false) : index_(index), left_(left), right_(right) {} int index_; bool left_; bool right_; }; int main(int argc, char const *argv[]) { #ifndef ONLINE_JUDGE freopen("699_i.txt", "r", stdin); freopen("uva_o.txt", "w", stdout); #endif int numLeaf; list<Node> nodes; // 当前所有未处理完的节点 int numCase = 0; int index; // 起始点从中间开始 while (true) { cin >> numLeaf; // 当待处理节点为空时, 若读入的是 -1, 则说明操作结束 // 若不是 -1, 则说明是新 case 开始 if (nodes.empty()) { if (numLeaf == -1) { break; } else { printf("Case %d:\n", ++numCase); index = NUM_PILE / 2; fill(PILES.begin(), PILES.end(), 0); PILES[index] += numLeaf; nodes.push_front(Node(index)); continue; } } // 取第一个待处理的出来, 先填左再填右, 并相应递增下标 Node& node = nodes.front(); if (numLeaf != -1) { if (!node.left_) { node.left_ = true; index = node.index_ - 1; } else { node.right_ = true; index = node.index_ + 1; } PILES[index] += numLeaf; } else { if (!node.left_) { node.left_ = true; } else { node.right_ = true; } } // 如果一个节点左右皆满, 则出栈 if (node.left_ && node.right_) nodes.pop_front(); // 除 -1 外的都需要入栈 if (numLeaf != -1) nodes.push_front(Node(index)); // 所有节点都处理完了, 就输出 // 必须是两个数之间有空格, 最后不能有空格, 否则 Presentation error if (nodes.empty()) { int j = 0; for (int i=0; i<NUM_PILE; i++) { if (PILES[i] != 0) { if (j > 0) cout << " "; cout << PILES[i]; ++j; } } cout << endl << endl; } } return 0; }
环境: C++ 4.5.3 - GNU C++ Compiler with options: -lm -lcrypt -O2 -pipe -DONLINE_JUDGE