【题目链接】

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个数字。
然后每行有一个合法的我们之前描述的逆波兰表达式,以“=”结束。“=”是计算的指令。每项不会超过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. 表达式树

表达式树:一棵表达式树可以表示一系列的运算。
表达式树中的结点包括运算符与数值

struct Node
{char c;//运算符int n;//数值
}
  • 分支结点:c:运算符,n:该子树对应的表达式的值
  • 叶子结点:c:'\0',n:数值
    表达式树的值,是左子树的值和右子树的值,经过根结点运算符运算后得到的结果。

【解题思路】

解法1:后缀表达式直接求值

  1. 从左向右扫描后缀表达式。
  2. 遇到数字时,将数字入栈。
  3. 遇到运算符时,弹出栈顶的两个数,用该运算符对它们做相应的计算,结果入栈。
  4. 扫描结束后,栈顶数字就是结果。

解法2:后缀表达式构造表达式树

  1. 如果读到数字,那么新建数字结点入栈。
  2. 如果读到运算符,则新建运算符结点np,出栈两个结点,将这两个结点的值通过np的运算符运算后得到的值存为新结点np的值,将np入栈。
  3. 读完整个后缀表达式,栈中应该只剩1个结点,该结点就是表达式树的根结点,该结点的值就是表达式的值 。

解法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相关推荐

  1. 信息学奥赛一本通 1232:Crossing River | OpenJudge NOI 4.6 702:Crossing River

    [题目链接] ybt 1232:Crossing River OpenJudge NOI 4.6 702:Crossing River 一本通里的翻译不够完整,OpenJudge中的英文原题中有对数据 ...

  2. 信息学奥赛一本通 1229:电池的寿命 | OpenJudge NOI 4.6 2469:电池的寿命

    [题目链接] ybt 1229:电池的寿命 OpenJudge NOI 4.6 2469:电池的寿命 [题目考点] 1. 贪心 [解题思路] 1. 贪心选择性质的证明 电池分配主要有两步, 第一步:将 ...

  3. 信息学奥赛一本通 1227:Ride to Office | OpenJudge NOI 4.6 2404:Ride to Office

    [题目链接] ybt 1227:Ride to Office OpenJudge NOI 4.6 2404:Ride to Office 原题是英文题,虽说两题题意相同,但一本通网站没有对该问题进行直 ...

  4. 信息学奥赛一本通 1194:移动路线 | OpenJudge NOI 2.6 2718:移动路线

    [题目链接] ybt 1194:移动路线 OpenJudge NOI 2.6 2718:移动路线 [题目考点] 1. 坐标型动态规划 [解题思路] 解法1:递推 设状态数组dp,dp[i][j]表示从 ...

  5. 信息学奥赛一本通 1193:吃糖果 | OpenJudge NOI 2.6 1944:吃糖果

    [题目链接] OpenJudge NOI 2.6 1944:吃糖果 注:ybt 1193:吃糖果 页面打不开,可以在OpenJudge做该题. [题目考点] 1. 递推/递归 2. 搜索 [解题思路] ...

  6. 信息学奥赛一本通 1191:流感传染 | OpenJudge NOI 2.3 6262:流感传染

    [题目链接] ybt 1191:流感传染 OpenJudge NOI 2.3 6262:流感传染 [题目考点] 1. 二维数组 2. 队列 [解题思路] 用一个字符型二维数组存储各个房间的情况. 1. ...

  7. 信息学奥赛一本通 1190:上台阶 | OpenJudge NOI 2.3 3525:上台阶

    [题目链接] ybt 1190:上台阶 OpenJudge NOI 2.3 3525:上台阶 注:ybt 1190最大数据数量为71,而OpenJudge 2.3 3525中最大数据数量为100.如果 ...

  8. 信息学奥赛一本通 1189:Pell数列 | 1202:Pell数列 | OpenJudge NOI 2.3 1788:Pell数列 | 2.3 1788:Pell数列

    [题目链接] ybt 1189:Pell数列 ybt 1202:Pell数列 OpenJudge NOI 2.2 1788:Pell数列 OpenJudge NOI 2.3 1788:Pell数列 [ ...

  9. 信息学奥赛一本通 1188:菲波那契数列(2) | OpenJudge NOI 2.3 1760:菲波那契数列(2)

    [题目链接] ybt 1188:菲波那契数列(2) OpenJudge NOI 2.3 1760:菲波那契数列(2) [题目考点] 1. 求斐波那契数列 多种方法求斐波那契数列 [解题思路] 该题可能 ...

最新文章

  1. 我用Java+SeimiCrawler+Redis+ES+Kibana技术对数百万知乎用户进行了数据分析,得到了这些......
  2. 深度学习调参tricks总结!
  3. Qt Creator中常用快捷键和小技巧
  4. Python:一篇文章掌握Numpy的基本用法
  5. python三种数据类型详解_最全面的Python数据类型知识点讲解
  6. 记crontab脚本未执行问题排查
  7. python的@classmethod和@staticmethod
  8. Ninject依赖注入(一)
  9. Mercurial hg web server的配置
  10. C语言 全局变量和局部变量区别 - C语言零基础入门教程
  11. 7-5 统计大写辅音字母 (15 分)
  12. Node.js 修复4个漏洞
  13. MySql数据库帮助类:DbHelperMySQL
  14. 多张图片合成一张jpg工具_比较好的拼图软件,多张图片合并工具
  15. P问题、NP问题、NPC问题、NPC-hard问题
  16. gg 修改器游戏被保护_2.游戏so防封的制作思路
  17. ChucK学习笔记(一)——下载与安装
  18. OAS ( Open Adoption Software ) 类公司的崛起
  19. I2C协议---I2C时序图解析
  20. i3 7100黑苹果_苹果连发三款新品,售价更低!性能更强!| 数码

热门文章

  1. Install and run DB Query Analyzer 6.04 on Microsoft Windows 10
  2. 05-类--+-号使用
  3. 使用WxPython进行Win32下Python编程
  4. JavaEE班第四天
  5. 中国高铁站,为什么离市区这么远
  6. 任正非:华为100%没有后门,没想到美国打击华为决心这么大
  7. python怎么用matplotlib_用Matplotlib在Python中绘制时间
  8. 是Dubbo不香了吗?阿里为啥又搞一套Spring Cloud Alibaba?
  9. 为什么 0.1 + 0.2 = 0.300000004
  10. 看程序员如何给女朋友解释什么是锟斤拷?