OpenJudge NOI 3.3 3340:RPN Calculator
【題目鏈接】
OpenJudge NOI 3.3 3340:RPN Calculator
【題目翻譯】
逆波蘭表示法計(jì)算器
描述
逆波蘭表示法與波蘭表示法類(lèi)似。波蘭表示法是由波蘭數(shù)學(xué)家揚(yáng)·武卡謝維奇于1920年引入的,是一種每個(gè)操作符都在它的操作數(shù)后面的數(shù)學(xué)表示法,它也被稱(chēng)作:前綴表示法。
在逆波蘭表示法中運(yùn)算符在它們的操作數(shù)后面;例如,要表示三加四,一個(gè)人應(yīng)該寫(xiě)“3 4 +”,而不是“3 + 4”。如果有多個(gè)運(yùn)算符,運(yùn)算符必須直接出現(xiàn)在它的第二個(gè)操作數(shù)后面。所以,用傳統(tǒng)的中綴表示法寫(xiě)出的“3 - 4 + 5”在逆波蘭表示法中寫(xiě)為“3 4 - 5 +”:先做3減4,再加5。逆波蘭表示法的好處是它避免了在一些中綴表示法中必須寫(xiě)的括號(hào)?!? - 4 * 5”也可以寫(xiě)為“3 - (4 * 5)”,它與“(3 - 4) * 5”的意義非常不同,只有使用括號(hào)才能區(qū)分二者的意義。在前綴表示法中,前面的一個(gè)表達(dá)式可以寫(xiě)為:“3 4 5 * -”,這也能無(wú)歧義第表示“3 (4 5 *)”
要求你設(shè)計(jì)一個(gè)簡(jiǎn)單的逆波蘭表達(dá)式計(jì)算器,需要支持+,?,?,/+, -, *, /+,?,?,/,(除數(shù)的絕對(duì)值不小于10?910^{-9}10?9)與^(乘方運(yùn)算符,如果底數(shù)b≤0b \le 0b≤0,那么指數(shù)eee一定是一個(gè)正數(shù)而且不大于10910^9109。
你可以認(rèn)為運(yùn)算中涉及到的所有的數(shù)字都可以由雙精度浮點(diǎn)型變量表示。
另外,我們的計(jì)算器有一些“內(nèi)存”。每次我們計(jì)算一個(gè)表達(dá)式,“內(nèi)存”中最小的數(shù)字會(huì)被當(dāng)前表達(dá)式的值替換掉。
輸入:
第一行包含一個(gè)整數(shù)n,表示計(jì)算器的“內(nèi)存”大小。
從第二行開(kāi)始,我們會(huì)給出n個(gè)數(shù)字,為“內(nèi)存”中的初始值。除了最后一行,每行會(huì)給出10個(gè)數(shù)字。
然后每行有一個(gè)合法的我們之前描述的逆波蘭表達(dá)式,以“=”結(jié)束。“=”是計(jì)算的指令。每項(xiàng)不會(huì)超過(guò)20個(gè)字符。
輸出:
對(duì)于每個(gè)表達(dá)式,在一行內(nèi)輸出它的值。
然后輸出一個(gè)空行分隔兩部分。
最后,以升序輸出內(nèi)存中的所有的數(shù)字,10個(gè)數(shù)字一行。
每個(gè)數(shù)字必須以科學(xué)計(jì)數(shù)法表示,整數(shù)小數(shù)點(diǎn)后保留6位,指數(shù)保留2位。(就像C語(yǔ)言中用printf("%e")格式化字符串一樣)一行中的各個(gè)數(shù)字應(yīng)該用空格分隔。
樣例輸入
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環(huán)境下指數(shù)部分為3位,在系統(tǒng)的測(cè)試環(huán)境下為2位。
【題目考點(diǎn)】
1. 表達(dá)式求值
2. 表達(dá)式樹(shù)
表達(dá)式樹(shù):一棵表達(dá)式樹(shù)可以表示一系列的運(yùn)算。
表達(dá)式樹(shù)中的結(jié)點(diǎn)包括運(yùn)算符與數(shù)值
- 分支結(jié)點(diǎn):c:運(yùn)算符,n:該子樹(shù)對(duì)應(yīng)的表達(dá)式的值
- 葉子結(jié)點(diǎn):c:'\0',n:數(shù)值
表達(dá)式樹(shù)的值,是左子樹(shù)的值和右子樹(shù)的值,經(jīng)過(guò)根結(jié)點(diǎn)運(yùn)算符運(yùn)算后得到的結(jié)果。
【解題思路】
解法1:后綴表達(dá)式直接求值
解法2:后綴表達(dá)式構(gòu)造表達(dá)式樹(shù)
解法3:遞歸
先將字符串處理為由結(jié)構(gòu)體對(duì)象構(gòu)成的后綴表達(dá)式,每個(gè)結(jié)構(gòu)體對(duì)象可能是數(shù)字可能是運(yùn)算符。
后綴表達(dá)式的結(jié)構(gòu)為:<第一個(gè)運(yùn)算單元><第二個(gè)運(yùn)算單元><運(yùn)算符>
每個(gè)運(yùn)算單元也許是一個(gè)數(shù)字,也許是一個(gè)后綴表達(dá)式。
后綴表達(dá)式數(shù)組最后一個(gè)元素的下標(biāo)為p。
設(shè)函數(shù)solve(),求從第p位置開(kāi)始向左遍歷取到的第一個(gè)運(yùn)算單元的值。每取一個(gè)元素,p向左移動(dòng)一個(gè)位置。
- 如果p位置是數(shù)字,直接返回這個(gè)數(shù)字的值。
- 如果p位置是運(yùn)算符,那么從p位置開(kāi)始向左取兩個(gè)運(yùn)算單元的值,并用當(dāng)前位置的運(yùn)算符進(jìn)行計(jì)算,得到這一運(yùn)算單元的值。
【題解代碼】
解法1:后綴表達(dá)式直接求值
#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()//求解后綴表達(dá)式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:輸出個(gè)數(shù) 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是數(shù)字(可能是負(fù)數(shù)) {eq[++p].n = atof(s);//將字符串s轉(zhuǎn)為浮點(diǎn)數(shù)。eq[p].c = '\0'; }else if(strcmp(s, "=") == 0)//遇到等號(hào),求解后綴表達(dá)式 {ans = solve();printf("%e\n", ans);pq.pop(); pq.push(ans);//將求解的結(jié)果存入堆 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()//求解后綴表達(dá)式eq {int lp = p--;if(eq[lp].c == '\0')//如果是數(shù)字 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:輸出個(gè)數(shù) 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是數(shù)字(可能是負(fù)數(shù)) {eq[++p].n = atof(s);//將字符串s轉(zhuǎn)為浮點(diǎn)數(shù)。eq[p].c = '\0'; }else if(strcmp(s, "=") == 0)//遇到等號(hào),求解后綴表達(dá)式 {ans = solve();printf("%e\n", ans);pq.pop(); pq.push(ans);//將求解的結(jié)果存入堆 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; }總結(jié)
以上是生活随笔為你收集整理的OpenJudge NOI 3.3 3340:RPN Calculator的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: android自动画线,Android画
- 下一篇: html树状图右侧_treeview-树