原题:
计算器的改良
时间限制: 1 Sec 内存限制: 125 MB题目描述
NCL是一家专门从事计算器改良与升级的实验室,最近该实验室收到了某公司所委托的一个任务:需要在该公司某型号的计算器上加上解一元一次方程的功能。实验室将这个任务交给了一个刚进入的新手ZL先生。
为了很好的完成这个任务,ZLZL先生首先研究了一些一元一次方程的实例:
4+3x=84+3x=8
6a-5+1=2-2a6a−5+1=2−2a
-5+12y=0−5+12y=0
ZLZL先生被主管告之,在计算器上键入的一个一元一次方程中,只包含整数、小写字母及+、-、=这三个数学符号(当然,符号“-”既可作减号,也可作负号)。方程中并没有括号,也没有除号,方程中的字母表示未知数。
你可假设对键入的方程的正确性的判断是由另一个程序员在做,或者说可认为键入的一元一次方程均为合法的,且有唯一实数解。
输入格式
一个一元一次方程。
输出格式
解方程的结果(精确至小数点后三位)。
输入输出样例
题意:
简单来说,就是输入一个一元一次方程,然后解它。
第一步:什么是一元一次方程?
答:唯一的未知数最高次项是1的方程,不懂的同学看这里。
也就是说,0x=9,1/x=1,x²=9......诸如此类都是不合法的!(虽然对解题好像没有什么用)
第二步:怎么做?
很明显这是一道模拟题,一般解方程的时候,老师会告诉我们,把一元一次方程化成一般形式ax=b,所以x=a/b。同理,我们得让计算机将它化成一般形式。
分离未知数(so easy):
if('a'<=str[i] && str[i]<='z') ch=str[i];//str代表一元一次方程,ch代表未知数
然后,基本思路是将方程按等号左右划分成两部分,等号左边的未知数的系数都当成正数,常数当成负数分别累加(相当于常数移项到右边),右边未知数系数当成负数移到左边,常数项当成正数累加(注释在代码中,右边也是同样的道理)。
for(int i=0;i<len;i++) { if(str[i]=='=') { con-=rec*op,rec=0,op=1,p=i+1; break; }//等号左边已处理完 if('0'<=str[i] && str[i]<='9') rec=rec*10+str[i]-'0';//rec记录并转化为十进制数 if('a'<=str[i] && str[i]<='z') { if(!rec) rec=1;//一个小小的坑点:未知数前可能没有数字 ch=str[i],coe+=rec*op,rec=0,op=1;//将系数累加,记录未知数,所有数据清空 } if(str[i]=='+') con-=rec*op,rec=0,op=1;//如果rec仍然有值,那么它必然是常数 if(str[i]=='-') con-=rec*op,rec=0,op=-1;//同上,做减法 }
几个陷阱
1.未知数的前面可能没有数字,系数是±1。
2.C++中,0除以一个负数答案是-0(特判,代码37行)。
3.符号刚开始要默认为是正。
4.未知数可能出现在右边,所以查找未知数的时候不能只查找左边。
5.一个漂亮的模拟就完成了╰(*°▽°*)╯
完整的代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 string str;//方程 6 char ch;//未知数 7 int p,op=1,rec,coe,con,len;//p 右半部分开端下标,op 正负号,rec 临时转化并储存数字,coe 系数,con 常数,len 方程长度 8 int main() 9 { 10 getline(cin,str); 11 len=str.length(); 12 for(int i=0;i<len;i++) 13 { 14 if(str[i]=='=') { con-=rec*op,rec=0,op=1,p=i+1; break; } 15 if('0'<=str[i] && str[i]<='9') rec=rec*10+str[i]-'0'; 16 if('a'<=str[i] && str[i]<='z') 17 { 18 if(!rec) rec=1; 19 ch=str[i],coe+=rec*op,rec=0,op=1; 20 } 21 if(str[i]=='+') con-=rec*op,rec=0,op=1; 22 if(str[i]=='-') con-=rec*op,rec=0,op=-1; 23 } 24 for(int i=p;i<len;i++) 25 { 26 if('0'<=str[i] && str[i]<='9') rec=rec*10+str[i]-'0'; 27 if('a'<=str[i] && str[i]<='z') 28 { 29 if(!rec) rec=1; 30 ch=str[i],coe-=rec*op,rec=0,op=1; 31 } 32 if(str[i]=='+') con+=rec*op,rec=0,op=1; 33 if(str[i]=='-') con+=rec*op,rec=0,op=-1; 34 } 35 con+=rec*op; 36 double ans=(double)con/(double)coe;//强制转化 37 if(!con) printf("%c=0.000",ch); 38 else printf("%c=%.3lf",ch,ans); 39 return 0; 40 }
一道有趣的模拟题,细节很多,建议练手。