699 - The Falling Leaves

题意:
落叶成堆, 一颗二叉树, 每个节点包含一定的叶子数, 上面的每个节点都会落下, 如果他们的垂直位置相同, 就会落成同一堆(叶子数叠加), 当所有节点掉落完后, 输出从左到右所有堆中的叶子个数.
(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

你可能感兴趣的:(uva,Leaves,the,699,Falling)