等价表达式
(equal.pas/c/cpp)
【问题描述】
明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。
这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
1. 表达式只可能包含一个变量‘a’。
2. 表达式中出现的数都是正整数,而且都小于10000。
3. 表达式中可以包括四种运算‘+’(加),‘-’(减),‘*’(乘),‘^’(乘幂),以及小括号‘(’,‘)’。小括号的优先级最高,其次是‘^’,然后是‘*’,最后是‘+’和‘-’。‘+’和‘-’的优先级是相同的。相同优先级的运算从左到右进行。(注意:运算符‘+’,‘-’,‘*’,‘^’以及小括号‘(’,‘)’都是英文字符)
4. 幂指数只可能是1到10之间的正整数(包括1和10)。
5. 表达式内部,头部或者尾部都可能有一些多余的空格。
下面是一些合理的表达式的例子:
((a^1) ^ 2)^3,a*a+a-a,((a+a)),9999+(a-a)*a,1 + (a -1)^3,1^10^9……
【输入文件】
输入文件equal.in的第一行给出的是题干中的表达式。第二行是一个整数n(2 <= n <= 26),表示选项的个数。后面n行,每行包括一个选项中的表达式。这n个选项的标号分别是A,B,C,D……
输入中的表达式的长度都不超过50个字符,而且保证选项中总有表达式和题干中的表达式是等价的。
【输出文件】
输出文件equal.out包括一行,这一行包括一系列选项的标号,表示哪些选项是和题干中的表达式等价的。选项的标号按照字母顺序排列,而且之间没有空格。
【样例输入】
( a + 1) ^2
3
(a-1)^2+4*a
a + 1+ a
a^2 + 2 * a * 1 + 1^2 + 10 -10 +a -a
【样例输出】
AC
【数据规模】
对于30%的数据,表达式中只可能出现两种运算符‘+’和‘-’;
对于其它的数据,四种运算符‘+’,‘-’,‘*’,‘^’在表达式中都可能出现。
对于全部的数据,表达式中都可能出现小括号‘(’和‘)’。
【思路】
带值判断+计算表达式。
本题的关键在于计算表达式的值,大体过程就是利用两个栈分别存储运算数和运算符。维护运算符栈中运算符的优先级总是由顶到下递减的。
遇到数字的时候将数读完存入opint,遇到a的时候换为值存入opint。
遇到运算符c的时候:如果opchar栈顶优先级比c小则将c存入opchar,如果相等则取出栈顶,如果栈顶的优先级更大则计算。
输入点中有个不满足正确性的表达式为 ()) 的形式,需要特殊处理一下。
还有一个点需要提到:题目中的数据如果有long long存的话任然会溢出,但并不需要因此加入高精计算,因为只是判断两个式子的结果是否相等,如果相等的话就算是溢出的结果也是相等的。
详见代码。
【代码】
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <stack> 6 using namespace std; 7 8 typedef long long LL; 9 const int maxn = 120+10; 10 11 char str[maxn], s1[maxn],s2[maxn]; 12 int nei[maxn*3], wai[maxn*3]; 13 LL T[10] = {11, 15, 18, 25, 29, 30, 36, 50, 55, 70}; 14 stack<char> opchar; 15 stack<LL> opint; 16 bool flag; 17 18 LL calculate(LL x, LL y, char c) 19 { 20 switch(c) 21 { 22 case '+': return x + y; 23 case '-': return x - y; 24 case '*': return x * y; 25 case '^': 26 LL tmp = 1; 27 for(int i = 0; i < y; i++) tmp *= x; 28 return tmp; 29 } 30 } 31 char cmp(char a, char b) 32 { 33 if(a=='#' && b==')') return '0'; //有一个点会出现 ())的情况 34 if(nei[a] > wai[b]) return '>'; 35 else if(nei[a] == wai[b]) return '='; 36 return '<'; 37 } 38 LL solve(char *s, LL t) 39 { 40 int i = 0; 41 while(s[i] != '#' || opchar.top() != '#') 42 { 43 LL num = 0; 44 if(!flag) return -1; 45 if(isdigit(s[i])) 46 { 47 while(isdigit(s[i])) 48 { 49 num = num*10+s[i] - '0'; 50 i++; 51 } 52 opint.push(num); 53 } 54 else if(s[i] == 'a') 55 { 56 opint.push(t); 57 i++; 58 } 59 else 60 { 61 switch(cmp(opchar.top(), s[i])) 62 { 63 case '<' : opchar.push(s[i]); i++; break; 64 case '=' : opchar.pop(); i++; break; 65 case '0' : i++; break; //特殊情况处理 66 case '>' : 67 if(opint.empty()) 68 { 69 flag = false; 70 return -1; 71 } 72 LL ta = opint.top(); 73 opint.pop(); 74 if(opint.empty()) 75 { 76 return ta; 77 } 78 LL tb = opint.top(); 79 opint.pop(); 80 LL S=calculate(tb, ta, opchar.top()); 81 opint.push(S); 82 //cout<<tb<<optr.top()<<ta<<'='<<S<<endl; 83 opchar.pop(); 84 break; 85 } 86 } 87 } 88 return opint.top(); 89 } 90 void init() 91 { 92 while(!opint.empty()) opint.pop(); 93 while(!opchar.empty()) opchar.pop(); 94 opchar.push('#'); //哨兵 95 } 96 int main() 97 { 98 nei['+'] = 2; wai['+'] = 1; 99 nei['-'] = 2; wai['-'] = 1; 100 nei['*'] = 4; wai['*'] = 3; 101 nei['^'] = 6; wai['^'] = 5; 102 nei[')'] = 8; wai[')'] = 0; 103 nei['('] = 0; wai['('] = 8; 104 nei['#'] = -1; wai['#'] = -1; 105 gets(str); 106 int len = 0; 107 for(int i = 0; str[i]; i++) 108 if(str[i] != ' ') s1[len++] = str[i]; 109 s1[len++] = '#'; //追加哨兵 110 s1[len] = '