您的位置:首页 > 编程语言 > C语言/C++

NOIP2000普及组 计算器的改良 Codevs1015 字符串复杂处理

2016-06-29 23:57 344 查看
http://codevs.cn/problem/1015/

题目大意:输入一个字符串,是一个一元一次方程。该方程只有整数、‘+’、‘-’、‘=’ 三个符号,其中‘-’既可以是负号也可以是减号。没有乘除号、括号和小数。常数和未知数之间的相乘,省略乘号或‘·’。要求输出方程的根,保留三位小数。

输入保证该方程合法,有且仅有一个实根。

样例输入 Sample Input

6a-5+1=2-2a

样例输出 Sample Output

a=0.750

大致思路:先确定代表未知数的字母。然后从左到右逐个字符进行讨论。分别存储常数项的和,以及未知数项的系数之和。在等号右边时,移项过后加变减,减变加。

处理较为繁杂,需细心考虑。

直接给出代码。(加了注释之后代码看起来很长。只是看起来)

#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
string s;
char x;<span style="white-space:pre"> </span>//表示未知数的字母
double dx=0,dk=0; //dx记录未知数的各项系数之和,dy记录所有常数项之和

bool is_alpha(char c) //判断某个字符是不是字母
{if ((c>='a' && c<='z')||(c>='A' && c<='Z')) return true; return false;}

bool is_num(char c) //判断某个字符是不是数字
{if (c>='0' && c<='9') return true; return false;}

void calc(int f,int sum,bool l,double &add){ //add 采用引用的形式,就不需要讨论加的是dx还是dk了
//f表示当前项正负,sum表示当前项常数之和,l表示在等号左边还是右边
if (l==1) add+=sum*f; //如果在等号左边,正常做加减
if (l==0) add-=sum*f; //如果在等号右边,由于移项,加变减,减变加
}

int main(){
cin>>s;

//确认代表未知数的字母
for (int i=0;i<s.length();i++)
if (is_alpha(s[i])) {
x=s[i];break;
}

bool l=1; //1表示在等号左边 , 0表示在等号右边
int f=1; //1表示当前项为正 , -1表示当前项为负
int sum=0; //当前项的常数值

for (int i=0;i<=s.length();i++){ //取等号是因为把所有字符都讨论完了之后还要再运算一次
if (i==s.length()) {calc(f,sum,l,dk); break;} //如上一行注释所说,如果是最后一次,只做运算,不讨论字符

char c=s[i];

//以下每行都写continue是为了整齐一点,不用写else

//如果是+或者-,之前必定已有一项结束,故先对之前一项进行计算,然后重置f和sum
if (c=='-') {calc(f,sum,l,dk); f=-1,sum=0; continue;}
if (c=='+') {calc(f,sum,l,dk); f= 1,sum=0; continue;}

/*如果是未知数,分两种情况:当sum=0时,意味着这个未知数项没有系数,要将系数修正为1;(数据里没有0x这样的项)
当sum!=0时,正常做加减即可。记得计算完之后修正f和sum。这样即使后面跟+或-,对常数的加减也是0,没有影响*/
if (c== x ) {if (sum==0) sum=1; calc(f,sum,l,dx); f= 1,sum=0; continue;}

//如果是数字,加sum就好了
if (is_num(c)) {sum*=10; sum+=c-'0'; continue;}

//碰到等号,修改l的值。不要忘了先进行一次计算
if (c=='=') {calc(f,sum,l,dk); l=0,f=1,sum=0; continue;}
}

printf("%c=%.3lf",x,-dk/dx); //由于以上的操作把常数项和未知数项都放在等号左边,所以求解时要加负号

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息