河南省acm第九届省赛--《表达式求值》--栈和后缀表达式的变形--手速题

表达式求值

时间限制: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
来源
河南省第九届省赛

大致思路:

用stack来实现的后缀表达式的解法。
每次需要考虑运算符的优先级,怎么考虑?
分类讨论:
1、顺序遍历表达式,当前符号位为加号时,判断上一位,是加号(同级),取num栈两个栈顶元素和op栈栈顶符号进行一次运算,再放回num栈中。
2、当前符号位为乘号,如果乘号的前后都是数字——那么一定可以进行乘法运算一次;由于在顺序遍历数组时,不方便预知后面一位是否为数字,可以在每次读入一位数字后进行判断;乘号的前后都是数字时,可以放心做乘。
3、当前符号位为S,Smax可以特殊处理,不存入“Smax”,只保留中间的', '  即可!把', '  号当做特殊运算符(类似与‘*’和‘+’)。
4、遇见左括号,存入;遇见右括号,开始进行计算一直计算到左括号,并把左括号删除。还有就是第三步', '的左右,进行运算时——要确保‘,’左右两边都是一个确定的数值!不然没法运算,所以对‘,’左边必须进行处理成一个整数!
5、加强版的样例 :

21
1+2
1+2+3
12*3+4*1*2
12*(1+3*4+1)

12*(2+3*1)+Smax(333,220*1+280)
12*(2+3)+(1+1*333,220*1+280)

题解:(有稍微的注释)

  1 #include<stdio.h>
  2 #include<math.h>
  3 #include<string.h>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<string>
  7 #include<stdlib.h>
  8 #include<map>
  9 #include<stack>
 10 #include<queue>
 11 #define inf 0x3f3f3f3f//19:04--
 12 #define N 1008
 13 #define ll long long
 14 using namespace std;
 15 stack<int>num;
 16 stack<char>op;
 17 char str[N];
 18 void cal(char opx){//依据opx来计算num栈上的前两位
 19     if(num.size()<=1)return ;
 20     int n1,n2;
 21         n1=num.top();num.pop();
 22         n2=num.top();num.pop();
 23     if(opx=='*')
 24         num.push(n1*n2);
 25     else if(opx=='+')
 26         num.push(n1+n2);
 27     else if(opx==','){
 28         int s1=0,s2=0;
 29         while(n1>0){
 30             s1+=n1%10;n1/=10;
 31         }
 32         while(n2>0){
 33             s2+=n2%10;n2/=10;
 34         }
 35         num.push(max(s1,s2));
 36     }
 37 }
 38 void cal2(char opx){//计算到左括号为止(Smax可以特殊处理:只保留中间的','即可!把','号当做特殊运算符)
 39     if(opx==','){
 40         while(op.top()!='('){
 41             cal(op.top());
 42             op.pop();
 43         }
 44       //  op.pop();
 45 
 46     }else{
 47         while(op.top()!='('){
 48             cal(op.top());
 49             op.pop();
 50         }
 51         op.pop();//去掉左括号
 52     }
 53 }
 54 int get_nextnum(int i){//分离出从str[]数组下标i开始的数字,注意要返回j
 55     int j,sum=str[i]-'0';
 56         for(j=i+1;j<strlen(str);j++){
 57             if(str[j]>='0'&&str[j]<='9')
 58                 sum=sum*10+str[j]-'0';
 59             else
 60                 break;
 61         }
 62         num.push(sum);
 63     return j;
 64 }
 65 
 66 void solve(){
 67     int ans=0;
 68     int len=strlen(str);
 69     for(int i=0;i<len;){
 70         if(str[i]==' ')
 71                 i++;
 72         else if(str[i]>='0'&&str[i]<='9'){
 73             i=get_nextnum(i);//获取该位置数字
 74             if(!op.empty()&&op.top()=='*'){//当读入一个数字后,发现上一位是乘号:及时做乘
 75                 cal('*');
 76                 op.pop();
 77             }
 78         }
 79         else if(str[i]=='*'){
 80                 op.push('*');
 81             i++;
 82         }
 83         else if(str[i]=='+'){
 84             if(!op.empty()&&op.top()=='+'){
 85                 cal(str[i]);//可以省略一push一次‘+’,毕竟先pop‘+’后push‘+’
 86             }
 87             else if(!op.empty()&&op.top()=='*'){
 88                 cal('*');
 89                 op.pop();
 90                 op.push('+');
 91             }
 92             else
 93                 op.push('+');
 94             i++;
 95         }
 96         else if(str[i]=='S'){
 97             i+=4;
 98         }
 99         else if(str[i]==','){
100              cal2(',');//计算到左括号!
101             op.push(str[i++]);
102         }
103         else if(str[i]=='('){
104              op.push(str[i++]);
105         }
106         else if(str[i]==')'){
107             cal2(')');
108             i++;
109         }
110     }
111 
112     while(op.size()>=1){
113         cal(op.top());
114         op.pop();
115     }
116 
117     ans=num.top();
118 
119     printf("%d
",ans);
120 }
121 
122 int main(){
123     int T;
124     scanf("%d
",&T);
125 
126     while(T--){
127         while(num.size()>0)num.pop();//清空整个num栈和op栈
128         while(op.size()>0)op.pop();
129         gets(str);
130         solve();
131     }
132 
133     return 0;
134 }
View Code
原文地址:https://www.cnblogs.com/zhazhaacmer/p/8777489.html