表达式求值
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
假设表达式定义为: 1. 一个十进制的正整数 X 是一个表达式。 2. 如果 X 和 Y 是 表达式,则 X+Y, X*Y 也是表达式; *优先级高于+. 3. 如果 X 和 Y 是 表达式,则 函数 Smax(X,Y)也是表达式,其值为:先分别求出 X ,Y 值的各位数字之和,再从中选最大数。 4.如果 X 是 表达式,则 (X)也是表达式。 例如: 表达式 12*(2+3)+Smax(333,220+280) 的值为 69。 请你编程,对给定的表达式,输出其值。
输入
【标准输入】 第一行: T 表示要计算的表达式个数 (1≤ T ≤ 10) 接下来有 T 行, 每行是一个字符串,表示待求的表达式,长度<=1000
输出
【标准输出】 对于每个表达式,输出一行,表示对应表达式的值。
样例输入
3
12+2*3
12*(2+3)
12*(2+3)+Smax(333,220+280)
样例输出
18
60
69
来源
河南省第九届省赛
去年我们队对于这道题有点懵比,因为我们用数组模拟的话,那情况就太特多了,五个小时也不一定可以把所有的情况写完,而且这样的话,代码肯定很长很长,估计出问题了,也不好找哪里错了,所有就没有过。
今年再次看到这道题,队友提醒说可以用数据结构的表达式求值来算,也就是把中缀表达式转换成前缀表达式或者后缀表达式(哎,只怪自己对数据结构学的还不够好啊)。
(如果不清楚中缀怎麼转换后缀的,请先看这篇文章文章)
这道题我是转换成后缀来算的,那么首先我们要知道后缀的结构,也就是操作数在前,操作运算符在后。
例如:(a+b)*c+d,把这个式子转成后缀为a#b#+#*#c#+#d#,之后我们再对后缀表达式求值即可。
但是这道题我们需要对 ' , ' 和' S '定义运算符的大小,这样有嵌套的时候不至于乱套。
那题目上的数据来说吧。
12*(2+3)+Smax(333,220+280)
按照规则中缀转后缀的规则我们可以知道转换之后的表达式为12#2#3#+#*#333#220#280#+#,#S#+#,再按照我们的计算规则就可以算出结果了,但是要是这一组数据呢,12*(2+3)+Smax(10+Smax(100,200),Smax(220+280,1000)),正确的后缀表达式应该是
12#2#3#+#*#10#100#200#,#S#+#220#280#+#1000#,#S#,#S#+#,为什么呢?因为如果里面有嵌套的话,那么我们一定要先把嵌套在里面的表达式求出来,这样再求外面的值。
Smax(10+Smax(100,200),Smax(220+280,1000)),如果我们没有定义‘ , ’和‘ S ’的运算符级别,那么后缀就会成为10#100#200#,#220#280#1000#,#+#S#,#S#+#S#,如果这样算的话,结果事不对的。
再和上面正确的后缀表达式比较,就可以再找出来不同了。
接下来,我们再对后缀表达式进行计算,从左往右找的时候,如果是操作数,那么就入栈,直到有运算符的时候,我们取栈的前两个元素,对他们进行运算,就这样一直找到最后即可,就能得到我们想要的答案了。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <cstring>
using namespace std;
char a[1005];
string S1,S2;
int jibie(char a)
{
int flag;
switch(a)
{
case 'S': flag = 4;break;
case ',': flag = 1;break;
case '+': flag=2;break;
case '-':flag=2;break;
case '*':flag=3;break;
case '/':flag=3;break;
default :flag=0;
}
return flag;
}
void conversion() ///把中缀表达式转换成后缀表达式
{
stack<char>Q;
char a;
a='#';
Q.push(a);
int i=0,m=S1.length();
while(i<m)
{
a=Q.top();
if(S1[i]=='('||S1[i]=='S')
{
if(S1[i]=='(')
{
Q.push(S1[i]);
i++;
}
else
{
Q.push(S1[i]);
i+=4;
//printf("^^^^^^%c\n",S1[i]);
}
}
else if(S1[i]==')')
{
while(a!='(')
{
S2=S2+a+'#';
Q.pop();
a=Q.top();
}
Q.pop();
i++;
}
else if(S1[i]=='+'||S1[i]=='-'||S1[i]=='*'||S1[i]=='/'||S1[i]==',')
{
while(jibie(a)>=jibie(S1[i]))
{
S2=S2+a+'#';
Q.pop();
a=Q.top();
}
Q.push(S1[i]);
i++;
}
else
{
//printf("************%c\n",S1[i]);
while((S1[i]>='0'&&S1[i]<='9')||S1[i]=='.')
{
S2=S2+S1[i];
i++;
}
S2+='#';
}
}
//cout << S1 << endl;
while(!Q.empty())
{
a=Q.top();
Q.pop();
if(a!='#')
{
S2=S2+a+'#';
}
}
cout<<S2<<endl;
}
void Zhi() ///对后缀表达式求值
{
int m=S2.length();
int i=0;
int num=0,a,b;
stack<int>W;
int num1=1;
while(i<m){
switch(S2[i])
{
case '+': a=W.top();W.pop();b=W.top();W.pop();a=a+b;W.push(a);i++;break;
case '-': a=W.top();W.pop();b=W.top();W.pop();a=b-a;W.push(a);i++;break;
case '*': a=W.top();W.pop();b=W.top();W.pop();a=a*b;W.push(a);i++;break;
case '/': a=W.top();W.pop();b=W.top();W.pop();a=b/a;W.push(a);i++;break;
case 'S':
{
a = W.top(); W.pop(); b = W.top(); W.pop();
int sum1 = 0, sum2 = 0;
//printf("a = %d, b = %d\n",a, b);
while(a!=0)
{
sum1 += a % 10;
a/=10;
}
while(b!=0)
{
sum2 += b % 10;
b/=10;
}
//printf("sum1 = %d sum2 = %d\n",sum1, sum2);
int maxn = max(sum1, sum2);
W.push(maxn);
i++;
break;
}
case ',': i++;break;
default:
{
if(S2[i]>='0'&&S2[i]<='9'&&num1==1){
num=num*10+S2[i]-'0';
if((S2[i+1]<'0'&&S2[i+1]!='.')||(S2[i+1]>'9'&&S2[i+1]!='.'))
{
//printf("bbbbbbbbbbb%lf\n",num);
W.push(num);
}
}
else if(S2[i]=='.') {
num1=num1*10;
}
else if(S2[i]>='0'&&S2[i]<='9'&&num1!=1) ///如果数据有小数 在这里处理
{
num=num+(S2[i]-'0')/(num1*1.0);
num1=num1*10;
if(S2[i+1]<'0'||S2[i+1]>'9'){
W.push(num);
//printf("bbbbbbbbbbb%lf\n",num);
}
}
else
{
num1=1;
num=0.0;
}
i++;
}
}
}
printf("%d\n",W.top());
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
getchar();
cin>>S1;
S2="";
conversion();
Zhi();
}
return 0;
}