POJ 1145 Tree Summing(樹)

POJ 1145 Tree Summing

題意: Lisp語言中表達一顆樹是用叫做S-expressions的方式來表達的,S-expressions有如下形式:

empty tree ::= ()
tree ::= empty tree (integer tree tree)

比如下圖這顆樹用S-expressions表達爲:

(5 (4 (11 (7 () ()) (2 () ()) ) ()) (8 (13 () ()) (4 () (1 () ()) ) ) )

在這裏插入圖片描述
給定一個整數和S-expressions表達的樹形式,問是否存在從根節點到葉節點路徑上的和等於給定的整數,有則輸出yes,無則輸出no。

注意: 本題輸入S-expressions時可能包含有多個空格和換行符,同時樹節點上的整數可能是負數

思路: 首先是讀取S-expressions,因爲含有換行符,讀取一行也不能完整讀入整個表達式,所以我採用getchar一次讀取一個,什麼時候讀取結束呢?輸入保證是合法的情況下,左括號’(‘和右括號’)'的數量是一樣的,所以每次讀取一個字符,同時可以跳過空白符,當讀取的左右括號數量一樣時可以斷定讀入了一個完整的S-expressions。

讀取得到完整的S-expression後,對S-expressions進行預處理,得到樹的先序遍歷序列,再根據先序遍歷序列建樹,最後在建立好的樹上進行遍歷

得到先序序列的方法:去掉非葉子節點的"(“和”)",對於葉子節點將“()”替換爲INF表示這是葉子節點,如對

(5 (4 (11 (7 () ()) (2 () ()) ) ()) (8 (13 () ()) (4 () (1 () ()) ) ) )

的先序序列爲:
在這裏插入圖片描述
建樹和遍歷都只需要使用遞歸即可。

代碼

#include <iostream>
#include <climits>
#include <cstdlib>
#include <vector>
#include <string>
#include <cstdio>
using namespace std;

#define INF = INT_MAX

class Node {
public:
    short data;
    Node* lchild;
    Node* rchild;
};

string get_string()
{
    int l_count = 0, r_count = 0;//已經讀入的左括號、右括號的數量
    string s;
    while (true)
    {
        char c = getchar();
        if (c == ' ' || c == '\n' || c == '\t') continue;//去掉空白符
        if (c == '(')l_count++;
        if (c == ')')r_count++;
        s += c;
        if (l_count == r_count) break;
    }
    return s;
}

vector<int> pre_order(const string& s) {
    vector<int> pre_rst;
    int i = 0;
    while (i < s.size()) {
        if (s[i] == '(') {
            if (s[i + 1] == ')')
                pre_rst.push_back(SHRT_MAX);//遇到()  空節點
            i++;
            continue;
        }
        if (s[i] == ')') {
            i++;
            continue;
        }

        //number
        int ends = i;
        while (s[ends] == '-' || isdigit(s[ends])) {
            ends++;
        }
        string substr = s.substr(i, ends - i);
        int num = atoi(substr.c_str());
        pre_rst.push_back(num);
        i = ends;//數字可能有多個字符,跳過多步
    }
    return pre_rst;
}

void build_tree(const vector<int>& pre_rst, int& index, Node*& root) {//注意後面兩個參數是引用,index是引用因爲對pre_rst的遍歷是順序的,不需要回退
    if (index >= pre_rst.size()) return;
    int num = pre_rst[index];
    if (num == SHRT_MAX) {
        return;
    }
    else {
        root = (Node*)malloc(sizeof(Node));
        root->lchild = NULL, root->rchild = NULL;//malloc完記得初始化
        root->data = num;
        index++;
        build_tree(pre_rst, index, root->lchild);
        index++;
        build_tree(pre_rst, index, root->rchild);
    }
}

void find_sum(Node* root, int num, int& sum, string& ans) {
    if (root == NULL) return;//單支空節點
    if (root->lchild == NULL && root->rchild == NULL) {//樹葉
        if (sum+root->data == num)
            ans = "yes";
        return;
    }
    sum += root->data;
    find_sum(root->lchild, num, sum, ans);
    find_sum(root->rchild, num, sum, ans);
    sum -= root->data;
}

int main()
{
    int N;
    while (cin >> N)
    {
        cin.ignore(1);
        string s = get_string();//讀入字符串,並且已經成功去除空格換行
        vector<int> pre_rst = pre_order(s);

        Node* ptr = NULL;
        int index = 0;
        build_tree(pre_rst, index, ptr);

        int sum = 0;
        string ans = "no";
        find_sum(ptr, N, sum, ans);
        cout << ans << endl;
    }
    return 0;
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章