NOIP 2005 等价表达式 (TYVJ P1060)

时间:2023-03-08 20:44:02

做题记录: 2016-08-10 23:35:09

背景

NOIP2005 提高组 第四道

描述

  明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。

  这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?

  这个选择题中的每个表达式都满足下面的性质:

  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……

对于30%的数据,表达式中只可能出现两种运算符‘+’和‘-’;

对于其它的数据,四种运算符‘+’,‘-’,‘*’,‘^’在表达式中都可能出现。

对于全部的数据,表达式中都可能出现小括号‘(’和‘)’。

输入格式

  输入的第一行给出的是题干中的表达式。第二行是一个整数n(2 <= n <= 26),表示选项的个数。后面n行,每行包括一个选项中的表达式。这n个选项的标号分别是A,B,C,D……

  输入中的表达式的长度都不超过50个字符,而且保证选项中总有表达式和题干中的表达式是等价的。

输出格式

  输出包括一行,这一行包括一系列选项的标号,表示哪些选项是和题干中的表达式等价的。选项的标号按照字母顺序排列,而且之间没有空格。 

测试样例1

输入

(a+ 1)^2 

(a -1)^ 2+4* a 
a +1+ a 
a^2 +2*a *1+1 ^2+ 10-10+a- a

输出

AC

代码

  

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
long long check,final;
long long num[],op[];
string s; long long power(long long a,long long b)
{
long long k=;
for(int i=;i<b;i++)
k*=a;
return k;
} void cul(int p,int op)
{
if(op==) num[p-]=num[p-]+num[p];
if(op==) num[p-]=num[p-]-num[p];
if(op==) num[p-]=num[p-]*num[p];
// if(op==3) num[p-1]=num[p-1]/num[p];
if(op==) num[p-]=power( num[p-],num[p] );
} long long result(string str){
int op_nxt;//下一个操作符
int len=str.length(),p=-,q=-;//p数字栈指针 ,q符号栈指针
long long num_nxt=;
for(int i=;i<len;i++){
if(str[i]=='a') num[++p]=check;
else if(str[i]>=''&&str[i]<='') num_nxt=num_nxt*+(str[i]-'');
else if(str[i]!=' '){
if(num_nxt!=){
num[++p]=num_nxt;
num_nxt=;
}
if(str[i]=='+') op_nxt=;
if(str[i]=='-') op_nxt=;
if(str[i]=='*') op_nxt=;
// if(str[i]=='/') op_nxt=3;
if(str[i]=='^') op_nxt=;
if(str[i]=='(') op_nxt=;
if(str[i]==')') op_nxt=;
if(op_nxt==) op[++q]=op_nxt;
else if(op_nxt==) while(q>=&&op[q--]!=) cul(p--,op[q+]);
else {
while(q>=&&op[q]<=&&op[q]/>=op_nxt/) cul(p--,op[q--]);
op[++q]=op_nxt;
}
}
}
//清空堆栈
if(num_nxt!=){
num[++p]=num_nxt;
num_nxt=;
}
while(q>=) cul(p--,op[q--]);
return num[];
} int main(){
freopen("01.txt","r",stdin);
string str1,str2;
int n;
final=;
getline(cin,str1);
cin>>n;
getline(cin,str2);
while(n--)
{
bool flag=true;
getline(cin,str2);
for (int i=;i<=;i++)
{
check=i;
if (result(str1)!=result(str2))
{
flag=false;
break;
}
}
if (flag) cout<<(char)('A'+final);
final++;
}
cout<<endl;
return ;
}

这题写了我老半天了,中间还睡着了好几次,非常困惑啊。

这题范围比较小,long long integer直接能过,像下面给出的其中一道题目就需要高精度。(假装我写了的样子~)

顺便附同类题目链接(TYVJ):

http://www.tyvj.cn/p/1043

http://www.tyvj.cn/Solution/8759

基本功还是要好好练练,为了提升代码阅读能力,仅给出主要注释。

表达式系列问题解答:

http://www.cnblogs.com/radiumlrb/p/5778357.html