描述
明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。
这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
1. 表达式只可能包含一个变量‘a’。
2. 表达式中出现的数都是正整数,而且都小于10000。
3. 表达式中可以包括四种运算‘+’(加),‘-’(减),‘*’(乘),‘^’(乘幂),以及小括号‘(’,‘)’。小括号的优先级最高,其次是‘^’,然后是‘x’,最后是‘+’和‘-’。‘+’和‘-’的优先级是相同的。相同优先级的运算从左到右进行。(注意:运算符‘+’,‘-’,‘*’,‘^’以及小括号‘(’,‘)’都是英文字符)
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……
对于30%的数据,表达式中只可能出现两种运算符‘+’和‘-’;
对于其它的数据,四种运算符‘+’,‘-’,‘*’,‘^’在表达式中都可能出现。
对于全部的数据,表达式中都可能出现小括号‘(’和‘)’。
格式
输入格式
输入的第一行给出的是题干中的表达式。第二行是一个整数n(2 <= n <= 26),表示选项的个数。后面n行,每行包括一个选项中的表达式。这n个选项的标号分别是A,B,C,D……
输入中的表达式的长度都不超过50个字符,而且保证选项中总有表达式和题干中的表达式是等价的。
输出格式
输出包括一行,这一行包括一系列选项的标号,表示哪些选项是和题干中的表达式等价的。选项的标号按照字母顺序排列,而且之间没有空格。
样例1
样例输入1
( a + 1) ^2
3
(a-1)^2+4*a
a + 1+ a
a^2 + 2 * a * 1 + 1^2 + 10 -10 +a -a
Copy
样例输出1
AC
Copy
限制
1s
来源
NOIp2005 第四题
这题很坑 不仅输入有空格 还要考虑括号不匹配的情况
现在暂借假设给出的表达式括号匹配
此题的做法是将字母a设为1,2,3,4,5算出原式的值
然后在将下面的表达式用a的1,2,3,4,5算出进行比较
这样这题就变成了一般的表达式求值题
由于算出数据可能很大 所以把算出的值每一步都取模
取模的数随便定 但是用10007比较好(10007是质数)
基本表达式求值见:*http://blog.csdn.net/xljer_/article/details/71610192*
//求值过程的注释与上一篇博客(表达式求值)一样 就不多说
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
//小于 -->计算 大于-->入栈
char r[9][9] = {
{' ','+','-','*','/','(',')','^','='},
{'+','>','>','<','<','<','>','<','>'},
{'-','>','>','<','<','<','>','<','>'},
{'*','>','>','>','>','<','>','<','>'},
{'/','>','>','>','>','<','>','<','>'},
{'(','<','<','<','<','<','=','<',' '},
{')','>','>','>','>',' ','>','>','>'},
{'^','>','>','>','>','<','>','>','>'},
{'=','<','<','<','<','<',' ','<','='},
};
char ss(char x,char y){
int a,b;
switch(x){
case '+':
a=1;
break;
case '-':
a=2;
break;
case '*':
a=3;
break;
case '/':
a=4;
break;
case '(':
a=5;
break;
case ')':
a=6;
break;
case '^':
a=7;
break;
case '=':
a=8;
break;
}
switch(y){
case '+':
b=1;
break;
case '-':
b=2;
break;
case '*':
b=3;
break;
case '/':
b=4;
break;
case '(':
b=5;
break;
case ')':
b=6;
break;
case '^':
b=7;
break;
case '=':
b=8;
break;
}
return r[a][b];
}
int ct(int x,int y,char ch){
switch(ch){
case '+':
return (x+y)%10007;
break;
case '-':
return (x-y)%10007;
break;
case '*':
return (x*y)%10007;
break;
case '/':
return (x/y)%10007;
break;
case '^':
if(x==0) return 0;
if(y==0) return 1;
int c=1;
for(int i=1;i<=y;i++){
c*=x;
c%=10007;
//由于乘方可能很大 所以每部都求余 不能使用pow了
}
return c;
break;
}
}
int opd[100],topd,topr=1,a,b,c;
char opr[100],ch,cch;
char s[55];
int ans[10];
int deal(int i){//因为要处理多次 将过程化为函数 i即a的值
int t=0;
topr=1,topd=0;
opr[1]='=';
ch=s[t++];
int flag=0;
while(!(ch=='='&&opr[topr]=='=')){
if(ch>='0'&&ch<='9'&&flag==0){
opd[++topd]=ch-48;
ch=s[t++];
flag=1;
}
while(ch>='0'&&ch<='9'&&flag==1) {
int x=opd[topd--];
x=x*10+ch-48;
opd[++topd]=x;
ch=s[t++];
}
flag=0;
if(ch=='a'){
opd[++topd]=i;
ch=s[t++];
}
//这里加一个判断 如果不加 输入单个数字的时候会卡死(等号不进行判断):
if(ch=='='&&opr[topr]=='=') return opd[1];
else if(!(ch>='0'&&ch<='9'))
switch(ss(opr[topr],ch)){
case '<':
opr[++topr]=ch;
ch=s[t++];
break;
case '>':
a=opd[topd--];
b=opd[topd--];
cch=opr[topr--];
c=ct(b,a,cch);
opd[++topd]=c;
break;
case '=':
topr--;
ch=s[t++];
break;
}
}
return opd[1];
}
char temp[55];
void makeinput(){//此函数是为了读入 过滤其空格
gets(temp);
int p=0;
int len=strlen(temp);
for(int i=0;i<len;i++){
if(temp[i]==' ') continue;
s[p++]=temp[i];
}
s[p]='=';
s[p+1]='\0';
}
int main(){
//freopen("equal8.in","r",stdin);
//freopen("answer.txt","w",stdout);
makeinput();
for(int i=1;i<=5;i++){
ans[i]=deal(i);
}
int n;
int pd=0;
scanf("%d",&n);
getchar();//这里的getchar很重要
for(int i=1;i<=n;i++){
pd=0;
makeinput();
for(int j=1;j<=5;j++){
int k=deal(j);
//cout<<k<<endl;
if(k!=ans[j])
{
pd=1;
break;
}
}
if(pd==1) continue;
else if(pd==0){
printf("%c",i+64);
}
}
return 0;
}