P1022 [NOIP2000 普及组] 计算器的改良

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

题目描述

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

  • 4+3�=84+3x=8。
  • 6�−5+1=2−2�6a−5+1=2−2a。
  • −5+12�=0−5+12y=0。

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

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

输入格式

一个一元一次方程。

输出格式

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

输入输出样例

输入 #1复制

6a-5+1=2-2a

输出 #1复制

a=0.750

这道题思维难度和代码难度都不大,就是细节处理有点麻烦,需要判断一些特殊情况(比如 --0.0什么的)。那我就直接上代码思路了。


因为是一元一次方程,所以最终一定可以化成 ��+�=0kx+b=0 的形式,整理可得 �=−��x=−kb​ ,为了减少变量数方便,将等号右边的多项式直接移到等式左边,即系数均乘 -1,可以用一个变量标记一下。


然后就是一连串的判断:

  1. 对于符号 ‘+’,‘-’,‘=’ 的处理
if(c=='-') {b+=now*f*x;x=0;f=-1;}
if(c=='+') {b+=now*f*x;x=0;f=1;}
if(c=='=') {b+=now*f*x;x=0;f=1;now=-1;}
这里 b 为常数部分的值;now 表示相对等号的位置,左边为 1 ,右边为 -1;f 表示项的系数的正负性,x 则是项的系数。

读到加号,常数累加,系数清零,符号标记为正,减号同理。读到等号则需额外将 now 改为 -1。
  1. 关于数字的读入
if(c>='0'&&c<='9') {x=x*10+c-'0';}
若判定为数字则叠加当前项系数。
  1. 关于未知数的处理
if(c>='a'&&c<='z') {k+=now*f*x;x=0;a=c;}
若判定为小写字母,则将未知数的系数累加,项系数清零,并标记未知数名 a。   

至此,这一题就成功的解决挂掉了。因为(变量 r 的含义还没讲呢!)还有

特殊情况

  1. 要是遇到 +x , -x 这种情况怎么办?

    那还不简单,系数为 0 就默认改为 1 就好了嘛。

    if(c>='a'&&c<='z')
    {
    	x?k+=now*f*x:k+=now*f;
        x=0;a=c;
    }
    

    那如果是 +0x , -0x 这种毒瘤情况又怎么办?

    这就需要引入一个新的变量 r 来标记是否有系数的读入。至于 r 的处理,只需要在读到数字时将 r 置为 1 ,读到其它字符都将 r 置为 0 就行了。

    if(c=='-') {b+=now*f*x;x=0;f=-1;r=0;}
    if(c=='+') {b+=now*f*x;x=0;f=1;r=0;}
    if(c=='=') {b+=now*f*x;x=0;f=1;now=-1;r=0;}
    if(c>='a'&&c<='z')
    {
    	if(r)
    	{
    		k+=now*f*x;x=0;
    	}
    	else k+=now*f;
    	a=c;r=0;
    }
    if(c>='0'&&c<='9') {x=x*10+c-'0';r=1;}
    
  2. 遇到 −�=0−x=0 这种情况总是输出 -0.0 怎么办?

    我就是这个原因死在了第五个点,看了题解才知道原来是因为 0 除以负数会被计算成 -0.0 。所以需要特判一下。

完整AC代码如下:

#include <iostream>
#include <cstdio>
using namespace std;
char c,a;//c用来读入,a是未知数名
int f=1,now=1,k,b,x;//f初始化为正,now初始为左,k、b、x意义如上
bool r;//用来判是否有数字读入
int main()
{
	while(cin>>c)//各种处理上面已经解释的很清楚了……(吧)
	{
		if(c=='-') {b+=now*f*x;x=0;f=-1;r=0;}
		if(c=='+') {b+=now*f*x;x=0;f=1;r=0;}
		if(c=='=') {b+=now*f*x;x=0;f=1;now=-1;r=0;}
		if(c>='a'&&c<='z')
		{
			if(r)
			{
				k+=now*f*x;x=0;
			}
			else k+=now*f;
			a=c;r=0;
		}
		if(c>='0'&&c<='9') {x=x*10+c-'0';r=1;}
	}
	b+=now*f*x;//加上最后一项常数(若最后一项是未知数则会加0)
    double ans=double(-b*1.0/k);
	if(ans==-0.0) ans=0;//特判,将-0.0改为0
	printf("%c=%.3lf",a,ans);//保留三位小数输出
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值