等价表达式
作者:互联网
等价表达式
描述
明明进了中学之后, 学到了代数表达式. 有一天, 他碰到一个很麻烦的选择题. 这个题目的题干中首先给出了一个代数表达式, 然后列出了若干选项, 每个选项也是一个代数表达式, 题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的.
这个题目手算很麻烦, 因为明明对计算机编程很感兴趣, 所以他想是不是可以用计算机来解决这个问题. 假设你是明明, 能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
表达式只可能包含一个变量'a'.
表达式中出现的数都是正整数, 而且都小于10000.
表达式中可以包括四种运算'+'(加), '-'(减), '**'(乘), '^'(乘幂), 以及小括号'(', ')'. 小括号的优先级最高, 其次是'^', 然后是'', 最后是'+'和'-'. '+'和'-'的优先级是相同的. 相同优先级的运算从左到右进行. (注意: 运算符'+', '-', '**', '^'以及小括号'(', ')'都是英文字符)
幂指数只可能是1到10之间的正整数(包括1和10).
表达式内部, 头部或者尾部都可能有一些多余的空格.
下面是一些合理的表达式的例子:
((a^1) ^ 2)^3, aa+a-a, ((a+a)), 9999+(a-a)a, 1 + (a -1)^3, 1109……*
- 对于30%的数据, 表达式中只可能出现两种运算符'+'和'-';
- 对于其它的数据, 四种运算符'+', '-', '*', '^'在表达式中都可能出现.
- 对于全部的数据, 表达式中都可能出现小括号'('和')'.
格式
输入格式
输入的第一行给出的是题干中的表达式. 第二行是一个整数n(2 <= n <= 26), 表示选项的个数. 后面n行, 每行包括一个选项中的表达式. 这n个选项的标号分别是A, B, C, D…… 输入中的表达式的长度都不超过50个字符, 而且保证选项中总有表达式和题干中的表达式是等价的.
输出格式
输出包括一行, 这一行包括一系列选项的标号, 表示哪些选项是和题干中的表达式等价的. 选项的标号按照字母顺序排列, 而且之间没有空格.
输入样例
( a + 1) ^2
3
(a-1)^2+4*a
a + 1+ a
a^2 + 2 * a * 1 + 1^2 + 10 -10 +a -a
输出样例
AC
虽然是同一道题,但这道题出现在了很多个不同的场所且具有不同的答案,本人在多个地方遇到了这个问题,其中AcWing还有这道题的讲解视频。
大概思路:如果我们直接去做这道题,是很难处理掉这个问题的,但我们可以采用一种曲线救国的方式,我们带入一些值进去算,将表达式中的a用1-1000的数去计算,如果一千个数都是正确,那我们大概率可以判定该表达式是正确的(在本题中,我们就可以判定该表达式正确),具体思路可以参考代码或者AcWing那位大神的讲解。
本人一开始的错误代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
int cale(string str,int a);
bool cherked(string str,string line);
int computer(int a,int b,char c);
int isGrade(char c);
const int P=13331;
stack<int> num;
stack<char> opr;
int cale(string str,int a)
{
num=stack<int>();
opr=stack<char>();
opr.push('#');
str+='$';
int len=str.size();
for(int i=0;i<len;++i)
{
if(str[i]==' ') continue;
else if(str[i]==')')
{
while(opr.top()!='(')
{
int b=num.top();
num.pop();
int s=num.top();
num.pop();
char c=opr.top();
opr.pop();
num.push(computer(s,b,c));
}
opr.pop();
}
else if(str[i]=='a') num.push(a);
else if(str[i]>='0'&&str[i]<='9')
{
int number=0;
int j=i;
while(j<len&&(str[j]>='0'&&str[j]<='9'))
{
number=number*10+str[j]-'0';
++j;
}
num.push(number);
i=j-1;
}
else if(str[i]=='('||isGrade(opr.top())<isGrade(str[i]))//逻辑错误位置
{
opr.push(str[i]);
}
else if(str[i]!='$')//逻辑错误位置
{
int b=num.top();
num.pop();
int s=num.top();
num.pop();
char c=opr.top();
opr.pop();
num.push(computer(s,b,c));
opr.push(str[i]);
}
else
{
while(opr.top()!='#')
{
int b=num.top();
num.pop();
int s=num.top();
num.pop();
char c=opr.top();
opr.pop();
num.push(computer(s,b,c));
}
}
}
//printf("%d\n",num.top());
return num.top();
}
int isGrade(char c)
{
if(c=='+'||c=='-')
return 2;
else if(c=='*'||c=='/')
return 3;
else if(c=='^')
return 4;
else if(c=='$')
return 1;
else if(c=='#')
return 0;
else return -1;
}
int computer(int a,int b,char c)
{
switch(c)
{
case '+':
return ((a+b)%P);
break;
case '-':
return (((a-b)%P+P)%P);
break;
case '*':
return ((a*b)%P);
break;
//case '/':
//return a/b;
//break;
case '^':
{
int s=a;
for(int i=1;i<b;++i)
{
a=(a*s)%P;
}
return a;
}
break;
}
return 0;
}
bool cherked(string str,string line)
{
for(int i=1;i<100;++i)//比较一百次
{
if(cale(str,i)!=cale(line,i))
return false;
}
return true;
}
int main()
{
string str;
int n;
getline(cin,str);
scanf("%d",&n);
fflush(stdin);
for(int i=0;i<n;++i)
{
string line;
getline(cin,line);
if(cherked(str,line))
{
printf("%c",'A'+i);
}
}
return 0;
}
错误总结:
在代码标注逻辑错误的地方,我错误的用了一个逻辑,但是当遇到的情况是(1-2a1-1)a=1时,我的写法会将返回0,因为在计算完2a1时,根据定义的运算符优先级会先用2-1,再用1-1,所以我的答案是0,但真实的答案却是-2
于是代码修改为如下:
解题答案:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
int cale(string str,int a);
bool cherked(string str,string line);
int computer(int a,int b,char c);
int isGrade(char c);
const int P=13331;
stack<int> num;
stack<char> opr;
int cale(string str,int a)
{
num=stack<int>();
opr=stack<char>();
opr.push('#');
str+='$';
int len=str.size();
for(int i=0;i<len;++i)
{
if(str[i]==' ') continue;
else if(str[i]=='(') opr.push(str[i]);
else if(str[i]>='0'&&str[i]<='9')
{
int number=0;
int j=i;
while(j<len&&(str[j]>='0'&&str[j]<='9'))
{
number=number*10+str[j]-'0';
++j;
}
num.push(number);
i=j-1;
}
else if(str[i]=='a') num.push(a);
else
{
if(str[i]!=')')
{
while(opr.top()!='#'&&isGrade(opr.top())>=isGrade(str[i]))
{
int b=num.top();
num.pop();
int s=num.top();
num.pop();
char c=opr.top();
opr.pop();
num.push(computer(s,b,c));
}
opr.push(str[i]);
}
else
{
while(opr.top()!='#'&&opr.top()!='(')
{
int b=num.top();
num.pop();
int s=num.top();
num.pop();
char c=opr.top();
opr.pop();
num.push(computer(s,b,c));
}
opr.pop();
}
}
}
//printf("%d\n",num.top());
return num.top();
}
int isGrade(char c)
{
if(c=='+'||c=='-')
return 2;
else if(c=='*'||c=='/')
return 3;
else if(c=='^')
return 4;
else if(c=='$')
return 1;
else if(c=='#')
return 0;
else return -1;
}
int computer(int a,int b,char c)
{
switch(c)
{
case '+':
return ((a+b)%P);
break;
case '-':
return (((a-b)%P+P)%P);
break;
case '*':
return ((a*b)%P);
break;
//case '/':
//return a/b;
//break;
case '^':
{
int s=a;
for(int i=1;i<b;++i)
{
a=(a*s)%P;
}
return a;
}
break;
}
return 0;
}
bool cherked(string str,string line)
{
for(int i=1;i<100;++i)//比较一百次
{
if(cale(str,i)!=cale(line,i))
return false;
}
return true;
}
int main()
{
string str,line;
int n;
getline(cin,str);
cin>>n;
getline(cin,line);
for(int i=0;i<n;++i)
{
getline(cin,line);
if(cherked(str,line))
{
printf("%c",'A'+i);
}
}
return 0;
}
其他版本:
#include<cstdio>
#include<cmath>
#include <iostream>
#include<cstring>
using namespace std;
char w[55],c[128];
int n,x,t1,t2,a[100];
long long check[5],c1[55],c2[55],c3[55];//用三个质数作为特殊值
int pow(int a,int b)
{
int s=a;
for (int i=2;i<=b;i++) s=(s*a+10007)%10007;//防止越界
return s;
}
void ys()//注意这是ys
{
int m1=c1[t2],n1=c1[t2-1],m2=c2[t2],n2=c2[t2-1],m3=c3[t2],n3=c3[--t2];
switch(w[t1])//同时对三个特殊值进行运算 数字栈为别为c1 c2 c3 符号栈为相同的w栈
{
case '+':c1[t2]=(n1+m1+10007)%10007; c2[t2]=(n2+m2+10007)%10007; c3[t2]=(n3+m3+10007)%10007; break;
case '-':c1[t2]=(n1-m1+10007)%10007; c2[t2]=(n2-m2+10007)%10007; c3[t2]=(n3-m3+10007)%10007; break;
case '*':c1[t2]=(n1*m1+10007)%10007; c2[t2]=(n2*m2+10007)%10007; c3[t2]=(n3*m3+10007)%10007; break;
case '^':c1[t2]=pow(n1,m1); c2[t2]=pow(n2,m2); c3[t2]=pow(n3,m3); break;
}
t1--;//运算完毕后运算符出栈
}
void js()
{
x=0;
for (int i=0;i<strlen(c);i++)
{
if (c[i]=='a')
{
c1[++t2]=3;//c[1]=3
c2[t2]=7;
c3[t2]=13;
} //是变量直接进栈
else if (c[i]>='0'&&c[i]<='9') x=x*10+c[i]-48;//可能有多位数字出现 在出现符号前进行累加
else//是字符进行处理
{
if (x!=0)
{
c1[++t2]=x;
c2[t2]=x;
c3[t2]=x;
x=0;
}//数字入栈
if (a[c[i]]==0) continue;
if (c[i]=='('||t1==0&&c[i]!=')') w[++t1]=c[i];//第一个操作符入栈
else
if (a[c[i]]<a[w[t1]])//当前读入字符优先级高
if (c[i]!=')')
w[++t1]=c[i];
else//不是右括号则进栈 若读进右括号要进行计算
{
while (w[t1]!='('&&t1>0) ys();//计算到左括号停止
if (w[t1]=='(') t1--;//左括号出栈
}
else//当前读入字符优先级低
{
while (a[c[i]]>=a[w[t1]]&&t1>0) ys();//将比当前字符优先级低的都计算完
if (c[i]!=')') w[++t1]=c[i];//读入的字符进栈
}
}
}
if (x!=0) {c1[++t2]=x; c2[t2]=x; c3[t2]=x; x=0;}
while (t1>0) ys();//将栈中剩下的同级运算符都做完
}
int main()
{
// freopen("equal.in","r",stdin);
// freopen("equal.out","w",stdout);
//设置各符号的优先级 数值越小优先级越高
a[40]=5;//表示(
a[41]=1;//表示)
a[94]=2;//表示幂
a[42]=a[47]=3;//表示* /
a[43]=a[45]=4;//表示+ -
t1=t2=0;//这句话不加也行,因为C++ 11标准,全局变量自动赋值为0
fgets( c, sizeof(c), stdin );
scanf("%d",&n);
js();
fgets( c, sizeof(c), stdin );//去回车
check[1]=c1[1];
check[2]=c2[1];
check[3]=c3[1];//以题干代数式得到的三个值为标准check
for (int i=1;i<=n;i++)
{
t1=t2=0;
fgets( c, sizeof(c), stdin );
js();
if (check[1]==c1[1]%10007&&check[2]==c2[1]%10007&&check[3]==c3[1]%10007)
printf("%c",i+64);//若三个质数运算得到的结果与标准相同则输出编号
}
fclose(stdin); //关闭输入流
fclose(stdout);//关闭输出流
return 0;
}
这段代码的基本逻辑:
如果是a,则用三个素数3 7 13进行替代计算,入栈,如果是数组,则用秦九韶算法求出原来数字,然后将其入栈,在将操作符入栈,如果遇到右括号则计算到遇到左括号为止(第一个是右括号除外),然后是将比当前字符优先级低的都计算完。
标签:opr,int,等价,num,str,include,表达式 来源: https://www.cnblogs.com/5-StarrySky/p/14642091.html