题解 P1022 【计算器的改良 】
teafrogsf
2017-08-24 16:20:37
## 此题不需要代码很长的模拟。
我们首先可以~~敏锐地~~发现,+的ASCII码值为43,-的ASCII码值为45,于是在判断是+还是-时,只需要算s[i]-44再乘个-1就可以了。
所有加减操作都可以在一个if里解决——当判断到符号时,**用存好的上一个符号结算在这个符号之前的那个数。**这种方法主要的难点是**特判**。
### ① 读入
读入的时候从1开始,0的位置添加一个加号,方便计算。循环中判定一下字母是什么。
### ② 等于号
检查到等于号时,将lor从1变为-1。\_lor是用于切换在方程左边还是右边的int。\_等于号直接变为加号就可以了,注意存一下等于号的位置。
### ③ 结果
将分子(整数和)和分母(未知数系数和)放在方程两边(在计算时的实现是son比mother**多乘一个-1**),直接相除即可。
### ④ 0
当一个未知数前面只有一个负号或正号(比如-x),系数为±1。需进行特判。同时,若这个数是0则它就是0,不能修改它。这一点详见代码,我是用是否走过循环来判定的。
### ⑤ 0.0(C/C++)
~~上面这个东西并不是表情符号。~~当0除以一个负数时,C/C++会默认将其判断成-0.0。所以要特判一下。
### ⑥ 计算过程
公式是son=x\*lor\*-1\*(s[pre]-44)\*-1,mother少一个-1。
### ⑦ 代码
如下。
```cpp
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define f(i,a,b) for(register int i=a;i<=b;++i)
bool flag,havenum;
char s[100010],ansx;
int son,mother,pre,lor=1,equal;
int main()
{
int len;
scanf("%s",s+1);
s[pre]='+';len=strlen(s+1);s[len+1]='+';//随便一个符号都可以
f(i,1,len+1)
{
if(s[i]>='a'&&s[i]<='z')ansx=s[i];
if(s[i]=='='||s[i]=='-'||s[i]=='+')
{
havenum=0;
if(i==1||i-1==equal){pre=i;continue;}
int j,x=0;
if(isdigit(s[i-1]))flag=0;
else flag=1;
for(j=pre+1;j<=i-1-flag;++j)
{x=(x<<1)+(x<<3)+(s[j]^'0');havenum=1;}
if(havenum==0)x=1;
if(flag==0)son+=x*lor*-1*(s[pre]-44)*-1;
else mother+=x*lor*(s[pre]-44)*-1;//ASCII - 45 + 43
//printf("%d %d %d %d\n",i,x,son,mother);
pre=i;
if(s[i]=='=')lor=-1,s[i]='+',equal=i;
}
}double ansy=double(son)/double(mother);if(fabs(ansy)-0.0<0.000001)ansy=0.0;
printf("%c=%.3lf",ansx,ansy);return 0;
}
```