计算器的改良(模拟)

原题:

计算器的改良

时间限制: 1 Sec  内存限制: 125 MB

题目描述

NCL是一家专门从事计算器改良与升级的实验室,最近该实验室收到了某公司所委托的一个任务:需要在该公司某型号的计算器上加上解一元一次方程的功能。实验室将这个任务交给了一个刚进入的新手ZL先生。

为了很好的完成这个任务,ZLZL先生首先研究了一些一元一次方程的实例:

4+3x=84+3x=8

6a-5+1=2-2a6a5+1=22a

-5+12y=05+12y=0

ZLZL先生被主管告之,在计算器上键入的一个一元一次方程中,只包含整数、小写字母及+、-、=这三个数学符号(当然,符号“-”既可作减号,也可作负号)。方程中并没有括号,也没有除号,方程中的字母表示未知数。

你可假设对键入的方程的正确性的判断是由另一个程序员在做,或者说可认为键入的一元一次方程均为合法的,且有唯一实数解。

输入格式

一个一元一次方程。

输出格式

解方程的结果(精确至小数点后三位)。

输入输出样例

输入
6a-5+1=2-2a
 
输出 
a=0.750

 


题意:

  简单来说,就是输入一个一元一次方程,然后解它。

 


 

  第一步:什么是一元一次方程?

  答:唯一的未知数最高次项是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 }

  一道有趣的模拟题,细节很多,建议练手。

  

 

原文地址:https://www.cnblogs.com/leaf-2234/p/14370391.html