OpenJudge NOI 3.3 3340:RPN Calculator
【題目鏈接】
OpenJudge NOI 3.3 3340:RPN Calculator
【題目翻譯】
逆波蘭表示法計算器
描述
逆波蘭表示法與波蘭表示法類似。波蘭表示法是由波蘭數學家揚·武卡謝維奇于1920年引入的,是一種每個操作符都在它的操作數后面的數學表示法,它也被稱作:前綴表示法。
在逆波蘭表示法中運算符在它們的操作數后面;例如,要表示三加四,一個人應該寫“3 4 +”,而不是“3 + 4”。如果有多個運算符,運算符必須直接出現在它的第二個操作數后面。所以,用傳統的中綴表示法寫出的“3 - 4 + 5”在逆波蘭表示法中寫為“3 4 - 5 +”:先做3減4,再加5。逆波蘭表示法的好處是它避免了在一些中綴表示法中必須寫的括號。“3 - 4 * 5”也可以寫為“3 - (4 * 5)”,它與“(3 - 4) * 5”的意義非常不同,只有使用括號才能區分二者的意義。在前綴表示法中,前面的一個表達式可以寫為:“3 4 5 * -”,這也能無歧義第表示“3 (4 5 *)”
要求你設計一個簡單的逆波蘭表達式計算器,需要支持+,?,?,/+, -, *, /+,?,?,/,(除數的絕對值不小于10?910^{-9}10?9)與^(乘方運算符,如果底數b≤0b \le 0b≤0,那么指數eee一定是一個正數而且不大于10910^9109。
你可以認為運算中涉及到的所有的數字都可以由雙精度浮點型變量表示。
另外,我們的計算器有一些“內存”。每次我們計算一個表達式,“內存”中最小的數字會被當前表達式的值替換掉。
輸入:
第一行包含一個整數n,表示計算器的“內存”大小。
從第二行開始,我們會給出n個數字,為“內存”中的初始值。除了最后一行,每行會給出10個數字。
然后每行有一個合法的我們之前描述的逆波蘭表達式,以“=”結束?!?#61;”是計算的指令。每項不會超過20個字符。
輸出:
對于每個表達式,在一行內輸出它的值。
然后輸出一個空行分隔兩部分。
最后,以升序輸出內存中的所有的數字,10個數字一行。
每個數字必須以科學計數法表示,整數小數點后保留6位,指數保留2位。(就像C語言中用printf("%e")格式化字符串一樣)一行中的各個數字應該用空格分隔。
樣例輸入
4
1e6 1e-6 0.001 1000
1 2 + 3 4 + * =
1 0.1 / 8 ^ =
樣例輸出
2.100000e+01
1.000000e+08
2.100000e+01 1.000000e+03 1.000000e+06 1.000000e+08
提示
有大量輸入,建議使用scanf()
%e格式輸出在windows環境下指數部分為3位,在系統的測試環境下為2位。
【題目考點】
1. 表達式求值
2. 表達式樹
表達式樹:一棵表達式樹可以表示一系列的運算。
表達式樹中的結點包括運算符與數值
- 分支結點:c:運算符,n:該子樹對應的表達式的值
- 葉子結點:c:'\0',n:數值
表達式樹的值,是左子樹的值和右子樹的值,經過根結點運算符運算后得到的結果。
【解題思路】
解法1:后綴表達式直接求值
解法2:后綴表達式構造表達式樹
解法3:遞歸
先將字符串處理為由結構體對象構成的后綴表達式,每個結構體對象可能是數字可能是運算符。
后綴表達式的結構為:<第一個運算單元><第二個運算單元><運算符>
每個運算單元也許是一個數字,也許是一個后綴表達式。
后綴表達式數組最后一個元素的下標為p。
設函數solve(),求從第p位置開始向左遍歷取到的第一個運算單元的值。每取一個元素,p向左移動一個位置。
- 如果p位置是數字,直接返回這個數字的值。
- 如果p位置是運算符,那么從p位置開始向左取兩個運算單元的值,并用當前位置的運算符進行計算,得到這一運算單元的值。
【題解代碼】
解法1:后綴表達式直接求值
#include <bits/stdc++.h> using namespace std; #define N 105 struct Node {double n;char c; }; Node eq[N]; int p; priority_queue<double, vector<double>, greater<double> > pq;//小頂堆 double calc(double a, double b, char c) {switch(c){case '+':return a+b;case '-':return a-b;case '*':return a*b;case '/':return a/b;case '^':return pow(a, b);} } double solve()//求解后綴表達式eq {stack<double> stk;for(int i = 1; i <= p; ++i){if(eq[i].c == '\0')stk.push(eq[i].n);else{double b = stk.top();stk.pop();double a = stk.top();stk.pop();stk.push(calc(a, b, eq[i].c));}}return stk.top(); } int main() {char s[25];double a, ans; int n, ct = 0;//ct:輸出個數 scanf("%d", &n);for(int i = 1; i <= n; ++i){scanf("%lf", &a);pq.push(a);}while(scanf("%s", s) != EOF){if(s[0] >= '0' && s[0] <= '9' || s[0] == '-' && s[1] >= '0' && s[1] <= '9')//如果s是數字(可能是負數) {eq[++p].n = atof(s);//將字符串s轉為浮點數。eq[p].c = '\0'; }else if(strcmp(s, "=") == 0)//遇到等號,求解后綴表達式 {ans = solve();printf("%e\n", ans);pq.pop(); pq.push(ans);//將求解的結果存入堆 p = 0;}else//是+-*/^ {eq[++p].n = 0;eq[p].c = s[0];}}putchar('\n');while(pq.empty() == false){ printf("%e ", pq.top());ct++;if(ct == 10){putchar('\n');ct = 0;}pq.pop();}return 0; }解法2:遞歸
#include <bits/stdc++.h> using namespace std; #define N 105 struct Node {double n;char c; }; Node eq[N]; int p; priority_queue<double, vector<double>, greater<double> > pq;//小頂堆 double calc(double a, double b, char c) {switch(c){case '+':return a+b;case '-':return a-b;case '*':return a*b;case '/':return a/b;case '^':return pow(a, b);} } double solve()//求解后綴表達式eq {int lp = p--;if(eq[lp].c == '\0')//如果是數字 return eq[lp].n;else{double b = solve();double a = solve();return calc(a, b, eq[lp].c);} } int main() {char s[25];double a, ans; int n, ct = 0;//ct:輸出個數 scanf("%d", &n);for(int i = 1; i <= n; ++i){scanf("%lf", &a);pq.push(a);}while(scanf("%s", s) != EOF){if(s[0] >= '0' && s[0] <= '9' || s[0] == '-' && s[1] >= '0' && s[1] <= '9')//如果s是數字(可能是負數) {eq[++p].n = atof(s);//將字符串s轉為浮點數。eq[p].c = '\0'; }else if(strcmp(s, "=") == 0)//遇到等號,求解后綴表達式 {ans = solve();printf("%e\n", ans);pq.pop(); pq.push(ans);//將求解的結果存入堆 p = 0;}else//是+-*/^ {eq[++p].n = 0;eq[p].c = s[0];}}putchar('\n');while(pq.empty() == false){ printf("%e ", pq.top());ct++;if(ct == 10){putchar('\n');ct = 0;}pq.pop();}return 0; }總結
以上是生活随笔為你收集整理的OpenJudge NOI 3.3 3340:RPN Calculator的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android自动画线,Android画
- 下一篇: html树状图右侧_treeview-树