题目
明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。
这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
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,110^9……
实现
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
#define mod 32767//因为计算结果可能会超出long long范围,所以计算时要模一个大质数
#define max_len 10//两个数要比较的次数
#define L 55 //输入的表达式长度在55以内
char s[L],b[L],n;//定义存储字符串 的数组
int ans[max_len+5];
int sumstack[L],fhstack[L];//数字栈和符号栈
int len1=0,len2=0;//栈的指针
int quick_mod(int x,int y)//x^y
{
int ret=1;
while(y)
{
if(y&1)
{
ret*=x;
ret%=mod;
}
y>>=1;x*=x;// y>>=1 二进制数向右移一位,相当于int型的/2
x%=mod;
}
return ret;
}
void multi()//对数字栈内两个数进行运算并弹出旧数,压入新结果
{
switch(fhstack[len2])
{
case 1:sumstack[len1-1]+=sumstack[len1];
sumstack[len1-1]%=mod;
break;
case 2:sumstack[len1-1]-=sumstack[len1];
sumstack[len1-1]%=mod;
break;
case 3:sumstack[len1-1]*=sumstack[len1];
sumstack[len1-1]%=mod;
break;
case 4:sumstack[len1-1]=quick_mod(sumstack[len1-1],sumstack[len1]);
sumstack[len1-1]%=mod;
break;
case 5:len2--; return;/*遇到左括号,直接跳过,是符号栈指针--*/
}
len1--;len2--;//数字栈和符号栈均弹出栈顶元素
}
int js(char s1[],int k)//传入字符串并使其中的a的值为k,使计算后的返回值为一个确值
{
memset(sumstack,0,sizeof(sumstack));//将数组中的值置0
memset(fhstack,0,sizeof(fhstack));
sumstack[1]=0;len1=1;//len1是数字栈指针 ,数字栈从2开始
len2=0;//len2是符号栈指针 ,符号栈从1开始
int len=strlen(s1);//求字符串长度并返回
for(int i=0;i<len;++i)
{
if(s1[i]==' ') continue;
if(s1[i]=='a')
{
sumstack[++len1]=k;//将a赋值为k
continue;
}
if(s1[i]>='0'&&s1[i]<='9')//将数字存入栈中,分两种情况,一位或多位
{
sumstack[++len1]=s1[i]-'0';
while(s1[i+1]>='0'&&s1[i+1]<='9')
{
sumstack[len1]=sumstack[len1]*10+s1[i+1]-'0';
sumstack[len1]%=mod;
i++;
}
continue;
}
switch(s1[i])//先传入一个符号,送入栈中,然后和下一个即将进栈的运算符进行比较,如果即将进栈的的运算符优先级比已经在栈里的运算符 优先级高,
//则不符合while()循环,若优先级低,则执行完while()循环再让它进栈,若优先级相等,则执行先进入的运算符号
{
case '(': fhstack[++len2]=5;break;//直接进栈
case '+':while(len2>0&&fhstack[len2]>0&&fhstack[len2]<5) multi();
fhstack[++len2]=1;
break;
/*注意这里的是while,不是if,就是如果满足条件的话,就把前面的一直算*/
case '-':while(len2>0&&fhstack[len2]>0&&fhstack[len2]<5) multi();
fhstack[++len2]=2;
break;
case '*':while(len2>0&&fhstack[len2]>2&&fhstack[len2]<5) multi();
fhstack[++len2]=3;
break;
case '^':while(len2>0&&fhstack[len2]>3&&fhstack[len2]<5) multi();
fhstack[++len2]=4;
break;
case ')':while(len2>0&&fhstack[len2]<5) multi();//遇到')'后将 栈里的符号依次弹出,并计算,直到遇到刚开始进栈的"(" ,
if(fhstack[len2]==5) len2--;// 然后把它也弹出,数据进入数据栈
break;
}
}
while(len2) multi();// 对符号中剩下的那个运算符处理
if(len1==1) return (sumstack[1]+mod)%mod;
return (sumstack[2]+mod)%mod;
}
void menu(){
printf("*****************************************************\n");
printf("********1.比较表达式是否相等******2.退出*************\n");
}
void find(){//输入方法
printf("输入两个要比较的表达式\n");
;
// gets(s);//读取字符串并放入数组s中
scanf("%s",s);
for(int i=1;i<max_len;++i){//i 的值表示a的取值 ,
ans[i]=js(s,i);//ans数组存储当a 的值为i时整个表达式的值
}
scanf("%s",b);
bool flag=true;
for(int i=1;i<max_len;++i)//进行10次判断,如果都符合,则相等
{
int x=js(b,i);
if(x!=ans[i])
{
flag=false;
break;
}
}
if(flag) {
printf("\n");
printf("相等\n");
printf("*****************************************************\n");
printf("\n");
printf("\n");
}
else{
printf("\n");
printf("不相等\n");
printf("*****************************************************\n");
printf("\n");
printf("\n");
}
}
int main()
{
int n;
while(1){
menu();
scanf("%d",&n);
if(n==2){
break;
}
else if(n==1){
find();
}
else{
printf("\n");
printf("输入错误!!!\n");
printf("\n");
printf("\n");
}
}
return 0;
}