10562 - Undraw the Trees

题意: 
把教授留下的立体的 tree 转化成线性的 tree, 每个节点的输出形式为 (A()), 若有子节点, 则按先左后右的顺序输出在紧跟 A 的括号里, 依次嵌套, 直至全部输出.

思路:
1. 建树, 这是一棵不规则的树, 所以使用 vector<Node*> children_ 来存放其子节点的指针;
(1). 每读入一个节点, 就判断它的正下方(即下一行相同 index 处) 是否有 '|', 有则说明它有子树;
(2). 在节点的正下下方(即下二行相同 index 处) 看其连续 '-' 所横跨的区间, 就是其子树所在的区间;
(3). 在节点的正下下下方(即下三行), 看 3 中所得到的区间内, 是否有节点(即不为 '-', '|', ' ',  '#'), 若有, 则递归创建子树, 并添加到 vector<Node*> children_ 中.

2. 打印树, 从根节点开始, 按 A(B()C()) 的形式递归打印. 最后在最外面再套一层 () 即可.

要点:
1. 注意有空树存在的情况, 此时直接输出 () 即可.
2. 一个节点, 其正下方必须有 '|' 才说明是有子节点的, 否则就是没有子节点的; 不考虑这一点, 会 WA.

题目:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=104&page=show_problem&problem=1503

代码:

# include <iostream>
# include <string>
# include <cstdio>
# include <cstring>
# include <vector>
# include <algorithm>
# include <cctype>
# include <iterator>
# include <sstream>
# include <assert.h>
# include <limits>
using namespace std;

class Node{
public:
  char c_;
  vector<Node*> children_;
};


// 判断 line[idx] 是否为一个合法的 Node, 即不能为  '-', '|', ' ' (space) and '#'
bool isNode(const string& line, int idx) {
  assert (idx < line.size());
  return (line[idx] != '-' &&
          line[idx] != '|' &&
          line[idx] != ' ' &&
          line[idx] != '#');
}

// 判断一个节点是否有 child, 即他的正下方必须是 |
// 一定要有这个判断, 否则 WA
bool hasChild(const vector<string>& lines, int numRow, int idx) {
  int r = numRow + 1;
  if (r >= lines.size() || idx >= lines[r].size()) return false;

  return (lines[r][idx] == '|');
}

// 获取 numRow 行, 第 idx 个数的子节点的下标范围
// first 是左下标, second 是右下标 (first, second)
// 如果不存在, 则返回 <-2, -2>
pair<int, int> getChildrenRange(const vector<string>& lines, 
                                int numRow, int idx) {
  // 它的下一行同样下标必须是 |
  if (!hasChild(lines, numRow, idx)) return make_pair(-2, -2);

  // 下标范围就在下两行
  int r = numRow + 2;
  if (r >= lines.size()) return make_pair(-2, -2);

  int first, second;
  for (first=idx; first>=0; first--) {
    if (lines[r][first] != '-') break;
  }

  for (second=idx; second<lines[r].size(); second++) {
    if (lines[r][second] != '-') break;
  }

  return make_pair(first, second);
}


// 获取 numRow 行, 第 idx 个数的子节点的下标
vector<int> getChildrenIndex(const vector<string>& lines, int numRow, int idx) {

  pair<int, int> range = getChildrenRange(lines, numRow, idx);
  if (range.first == range.second) return vector<int>();

  // 子节点在下三行
  int r = numRow + 3;
  if (r >= lines.size()) return vector<int>();

  vector<int> childrenIndex;
  for (int i=0; i<lines[r].size(); i++) {
    if (i > range.first && i < range.second && isNode(lines[r], i)) {
      childrenIndex.push_back(i);
    }
  }

  return childrenIndex;
}


// lines 是所有读入行, numRow 指的是当前操作行, idx 指的是操作数的下标
Node* buildTree(const vector<string>& lines, int numRow, int idx) {
  assert(numRow < lines.size());

  Node* root = new Node();
  root->c_ = lines[numRow][idx];

  vector<int> childrenIndex = getChildrenIndex(lines, numRow, idx);
  for (int i=0; i<childrenIndex.size(); i++) {
    // 子节点在下三行
    Node* child = buildTree(lines, numRow+3, childrenIndex[i]);
    (root->children_).push_back(child);
  }

  return root;
}

// 打印树
void printTree(Node* root) {
  if (root == NULL) return;

  printf("%c(", root->c_);

  vector<Node*>& children = root->children_;
  for (int i=0; i<children.size(); i++) {
    printTree(children[i]);
  }

  printf(")");
}

// 释放树空间
void freeTree(Node* root) {
  if (root == NULL) return;

  vector<Node*>& children = root->children_;
  for (int i=0; i<children.size(); i++) {
    delete children[i];
  }

  delete root;
}

int main(int argc, char const *argv[])
{
  #ifndef ONLINE_JUDGE
    freopen("10562_i.txt", "r", stdin);  
    freopen("uva_o.txt", "w", stdout); 
  #endif
  
  int numTree;
  cin >> numTree;
  cin.ignore();

  while (numTree--) {
    vector<string> lines;

    string line;
    int i = 0;
    while (getline(cin, line)) {
      if (line[0] == '#') break;
      lines.push_back(line);
    }

    if (lines.empty()) {
      cout << "()" << endl;
      continue;
    }

    int idx;
    // 获取第一个操作数, 建树
    for (idx=0; idx<lines[0].size(); idx++) {
      if (isNode(lines[0], idx)) break;
    }
    Node* root = buildTree(lines, 0, idx);

    //输出
    cout << "(";
    printTree(root);
    cout << ")" << endl;

    // 释放空间
    freeTree(root);
  }

  return 0;
}

环境:  C++ 4.5.3 - GNU C++ Compiler with options: -lm -lcrypt -O2 -pipe -DONLINE_JUDGE

你可能感兴趣的:(uva,the,trees,10562,Undraw)