• 计算器的改良(模拟)


    原题:

    计算器的改良

    时间限制: 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 }

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

      

     

  • 相关阅读:
    线性代数基础知识的复习
    第一个机器学习算法:线性回归与梯度下降
    初识机器学习
    VScode中LeetCode插件无法登录的情况
    内存管理-内存管理功能
    分组密码
    Linux进程调度
    进程调度
    死锁
    临界区和缩
  • 原文地址:https://www.cnblogs.com/leaf-2234/p/14370391.html
Copyright © 2020-2023  润新知