題意: 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;
}