vijos 1003 等价表达式

这题考的是字符串处理,然而十分繁琐,需要一定的技巧,还要十分注重细节

###算法
二分法——不断地寻找当前优先级最低的运算符,然后以它为中心将算式分成两段递归计算。
带入求值——因为要用多项式乘法对算式进行展开计算的话,不仅程序冗长繁琐,而且程序执行效率也十分低下。由于OI比赛的题目只有十组测试点,而且是按点得分,所以我们可以考虑用具体数字带入a求表达式的值来判断。为了减少误差,必须多取几个值。

###细节问题
1. 如果带入整数,由于幂指数很高,所以有上溢的风险,必须加上取模,当然这是建立在对模算术熟悉的基础上。在这里笔者带入的是小浮点数,可以巧妙地避免溢出。
1. 带入小数就产生了如何比较两个小数相等的问题。小数大小不能用等号直接比较,这应该属于常识了。而常用的方法(比较差是否小于eps,eps一般去10的-6次到10的-9次不等),在这数量级悬殊的数字比较上也无能为力。所以我们可以先比较它们的数量级(log10的值)是否相同,再去比较值。然而这种方法实测时误差不小,请尽量少在别的题目中使用。
1. 题目中的表达式可能会出现多括号、少括号的情况,必须自己把括号补上。
1. 此题的读入也十分猥琐。由于空格的存在所以不能用scanf直接读取了,C++必须gets\fgets\getline,然后自己慢慢处理吧……

###标程

#include <cstdio>
#include <cstring>
#include <cmath>

double A; // 代表用来替代a的值

class expr
{
public:
char s[100],ts[100];
double getnum(int l,int r) // 获取数字
{
int i,x=0;
for (i=l;i<=r;i++)
x=x*10+(int)s[i]-48;
return (double)x;
}
double calc(int l,int r) // 计算从l到r的表达式的值
{
int i,k;
for (i=r,k=0;i>=l;i--) // 从优先级最低的加减号开始
{
if (k==0)
{
if (s[i]==‘+‘)
return calc(l,i-1)+calc(i+1,r);
else if (s[i]==‘-‘)
return calc(l,i-1)-calc(i+1,r);
}
if (s[i]==‘(‘) k++;
else if (s[i]==‘)‘) k--;
}
for (i=r,k=0;i>=l;i--) // 处理乘号
{
if (k==0)
if (s[i]==‘*‘)
return calc(l,i-1)*calc(i+1,r);
if (s[i]==‘(‘) k++;
else if (s[i]==‘)‘) k--;
}
for (i=r,k=0;i>=l;i--) // 处理乘方
{
if (k==0)
if (s[i]==‘^‘)
return pow(calc(l,i-1),calc(i+1,r));
if (s[i]==‘(‘) k++;
else if (s[i]==‘)‘) k--;
}
if (s[l]==‘(‘&&s[r]==‘)‘) // 处理括号
return calc(l+1,r-1);
if (l==r&&s[l]==‘a‘) // 用A替代字母a的值
return A;
else
return getnum(l,r);
}
void scan() // 读入字符串并进行预处理
{
int i,j,k;
memset(ts,0,sizeof(ts));
memset(s,0,sizeof(s));
fgets(ts,sizeof(ts),stdin);
for (i=0,j=0,k=0;i<strlen(ts);i++)
if (ts[i]!=‘ ‘&&ts[i]!=‘\n‘) // 过滤空格和fgets读到的换行符
{
if (ts[i]==‘(‘&&ts[i-1]==‘)‘) // 在两个相邻的括号之间添加乘号
s[j++]=‘*‘;
else if (ts[i]==‘a‘&&ts[i-1]>=‘0‘&&ts[i-1]<=‘9‘) // 在a与它的系数之间添加乘号
s[j++]=‘*‘;
if (ts[i]==‘(‘) k++;
else if (ts[i]==‘)‘) k--; // 统计括号数目
s[j++]=ts[i];
}
if (k>0) while (k--) s[j++]=‘)‘; // 如果左括号多了,补充右括号
else if (k<0) // 如果有括号多了,补充左括号(这里用的方法很低效,应该还有更好的方案)
{
memset(ts,0,sizeof(ts)); j=0;
while (k++) ts[j++]=‘(‘;
strcat(ts,s);
memset(s,0,sizeof(s));
strcpy(s,ts);
}
}
double work() // 计算表达式的值
{
return calc(0,strlen(s)-1);
}
};

bool cmp(double a,double b) // 比较两个浮点数是否相等(这个方法误差其实很大)
{
int x,y;
double r;
x=(int)log10(a)+1;y=(int)log10(b)+1;
if (x!=y) return false;
r=pow(10,x-12);
if (fabs(a-b)>r) return false;
return true;
}

double P1,P2,P3,Q1,Q2,Q3;
int N,i;
expr S;
char ss[100];

int main()
{
S.scan();
A=0.7; P1=S.work();
A=1.4; P2=S.work();
A=2.1; P3=S.work();
fgets(ss,sizeof(ss),stdin);
sscanf(ss,"%d",&N); // 读入N
for (i=1;i<=N;i++)
{
S.scan();
A=0.7; Q1=S.work();
A=1.4; Q2=S.work();
A=2.1; Q3=S.work();
if (cmp(P1,Q1)&&cmp(P2,Q2)&&cmp(P3,Q3))
printf("%c",(char)(64+i));
}
}

时间: 2024-08-29 11:23:59

vijos 1003 等价表达式的相关文章

数据结构--栈 codevs 1107 等价表达式

codevs 1107 等价表达式 2005年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的. 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这

等价表达式

栈的经典题目,开两个栈,一个存符号,一个存数字: 分情况讨论: 1.如果当前读到的运算符优先级小于栈顶,就进行一次运算,直到大于等于: 2.如果读到数字用类似读入优化的方法读入进来: 3.如果当前符号为"("则直接入栈: 4.如果当前符号为")"则进行运算直到碰到"(": 5.小技巧 在式子开头加"(",末尾加")": 6.遇到a,让a等于质数: 7.多次取模,因为有可能爆long long,模不同的质数,

1107 等价表达式

1107 等价表达式 2005年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的. 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来

和指针相关的两个特殊运算符,和相关的等价表达式

和指针相关的两个特殊运算符: 一."&" 取地址运算符,通过&运算符可以取出普通变量的地址: 二."*"  有两种意义: 1.  为指针标志: 是否为指针标志主要看前面是否有类型,此处有一个int 2.  为指针运算符:    在等号右面为取值.*可以取出指针变量所指向的普通变量的值.   在等号左面为赋值.*可以将指针变量所指向的普通变量的值,修改为其他. 3.  为乘法运算符.当且仅当左右的都为变量时.略. 如 int a, b =20, c=3

NOIP2005 等价表达式 解题报告

明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的. 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题.假设你是明明,能完成这个任务吗? 这个选择题中的每个表达式都满足下面的性质: 1.  表达式只可能包含一个变量‘a’. 2.  表达式中出现的数都是正整数,而且都小于10000. 3.

等价表达式(noip2005)

3.等价表达式 [问题描述]    兵兵班的同学都喜欢数学这一科目,中秋聚会这天,数学课代表给大家出了个有关代数表达式的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的.    这个题目手算很麻烦,因为数学课代表对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题.假设你是数学课代表,能完成这个任务吗? 这个选择题中的每个表达式都满足下面的性质: 1. 表达式只可能包含一个变量

等价表达式(codevs 1107 答案错误)

题目描述 Description 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的. 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题.假设你是明明,能完成这个任务吗? 这个选择题中的每个表达式都满足下面的性质:1.表达式只可能包含一个变量‘a’.2.表达式中出现的数都是正整数,而且都

NOIP2005 等价表达式

做题记录: 2016-08-10 23:35:09 背景 NOIP2005 提高组 第四道 描述 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的. 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题.假设你是明明,能完成这个任务吗? 这个选择题中的每个表达式都满足下面的性质: 1.  

[Codevs 1107][NOIP 1107]等价表达式

题目连接:http://codevs.cn/problem/1107/ 一道很神奇的题目.对于算术表达式一类的问题,可以采用编译原理里的后缀表达式的方式来做,具体做法是分别维护两个栈,一个栈里保存表达式里的数字,另一个栈里保存表达式里的运算符,给每种运算符一个优先级,我们要维护这个栈的单调性,每次读入运算符中的数字或运算符,读入的是运算符时,若这个运算符比栈顶的运算符优先级低,就弹出栈顶元素,把栈顶的运算符和数字栈里栈顶的两个数字拿出来做一次运算,运算结果再入数字栈,直到运算符栈的栈顶元素优先级