您的位置:首页 > 其它

洛谷Oj-P1022 计算器的改良-字符串

2018-03-02 09:26 148 查看
题目背景:

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

题目描述:

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

4+3x=8

6a-5+1=2-2a

-5+12y=0

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

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

AC代码:

double a,b;//将方程转化为ax=b的形式
char x;//未知数
void work(string s,bool dir,bool sym)//子串s1,左边true右边false,正号true负号false
{
if(s.find(x) == string::npos)//子串中不含有未知数
{
if(dir == true && sym == true || dir == false && sym == false)//对b操作
b -= atoi(s.c_str());
else
b += atoi(s.c_str());
}
else//子串中含有未知数
{
if(dir == true && sym == true || dir == false && sym == false)//对a操作
{
if(s[0] == x)//特判形如a,+a,-a的情况
a += 1;
else
a += atoi(s.c_str());
}
else
{
if(s[0] == x)//特判形如a,+a,-a的情况
a -= 1;
a -= atoi(s.c_str());
}
}
return;
}
int get_the_first_symbol(string s)//获得第一个加减号所在的位置,失败返回-1
{
int len = s.length();
for(int i = 0; i <= len - 1; ++i)
if(s[i] == '+' || s[i] == '-')
return i;
return -1;
}
int get_the_last_symbol(string s)//获得最后一个加减号所在的位置,失败返回-1
{
int len = s.length();
for(int i = len - 1; i >= 0; --i)
if(s[i] == '+' || s[i] == '-')
return i;
return -1;
}
int get_the_second_symbol(string s)//返回第二个加减号所在的位置,失败返回-1
{
int len = s.length();
for(int i = get_the_first_symbol(s) + 1; i <= len - 1; ++i)
if(s[i] == '+' || s[i] == '-')
return i;
return -1;
}
void find_x(string s)//找出未知数
{
int len = s.length();
for(int i = 0; i <= len - 1; ++i)
if('a' <= s[i] && s[i] <= 'z')
{
x = s[i];
break;
}
return;
}
void solve(string s,bool dir)//核心的函数
{
int len = s.length();//表达式的长度
int first = get_the_first_symbol(s);//获得第一个加减号所在的位置
int second = get_the_second_symbol(s);//获得第二个加减号所在的位置
int last = get_the_last_symbol(s);//获得最后一个加减号所在的位置
if(first == -1 && second == -1 && last == -1)//特判形如5x=3x-1的情况,对于5x来说,返回值均为-1
{
work(s,dir,true);//直接处理s
return;
}
if(first == 0 && second == -1 && last == 0)//特判形如-5x=3x-1的情况,对于-5x来说,返回值只有second为-1
{
work(s.substr(1,len - 1),dir,false);
return;
}
{//完美解决第一项
if(first == 0)//说明表达式第一项为负数项
work(s.substr(1,second - 1),dir,false);
else//说明表达式第一项为正数项
work(s.substr(0,first),dir,true);
}
//完美解决最后一项
work(s.substr(last + 1,len - 1 - last),dir,s[last] < 44);//‘+’的ASCII码值为43,‘-’的ASCII码值为45
{//完美解决中间部分
int cur_pos_of_symbol;//当前符号所在的位置
if(first == 0)//表达式第一项为负数项的情况
cur_pos_of_symbol = second;
else//表达式第一项为正数项的情况
cur_pos_of_symbol = first;
int next_pos_of_symbol;//下一个符号所在的位置
while(cur_pos_of_symbol != last)
{
for(int i = cur_pos_of_symbol + 1; i <= len - 1; ++i)//找出下一个符号所在的位置
if(s[i] == '+' || s[i] == '-')
{
next_pos_of_symbol = i;
break;
}
work(s.substr(cur_pos_of_symbol + 1,next_pos_of_symbol - cur_pos_of_symbol - 1),
dir,s[cur_pos_of_symbol] < 44);
cur_pos_of_symbol = next_pos_of_symbol;//迭代
}
}
return;
}
int main()
{
string s;
cin >> s;//输入表达式
int len = s.length();//表达式的长度
int pos = s.find('=');//找出等号的下标
string s1 = s.substr(0,pos);//等号左边的表达式
string s2 = s.substr(pos + 1,len - (pos + 1));//等号右边的表达式
find_x(s);//找出未知数
solve(s1,true);
solve(s2,false);
if(b == 0)//因为当0除以一个负数时,C/C++会默认将其判断成-0.0,所以要特判一下
printf("%c=0.000\n",x);//按照题目的要求,应该是0.000!!!
else
printf("%c=%.3f\n",x,b / a);
return 0;
}


经验总结:

①要十分注意s.substr(a,b)是从s[a]开始(包括s[a])连续b个字符组成的字符串

②注意程序的普适性,最后再自己出几个特殊情况,考虑是不是应该在程序里加一些特判

③将功能函数化会使得程序更加简洁,思路更加清晰
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: