http://acm.hdu.edu.cn/showproblem.php?pid=1237
分析:题目思路有,就是先中缀转后缀,然后计算后缀表达式即可。
WA:思路是正确
#include<iostream>
using namespace std;
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<set>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<sstream>
string str; //中缀表达式
stack<string> s; //操作符栈
queue<string> q; //后缀表达式序列
map<string, int> mp; //操作符和优先级的映射
void change(){ //将中缀表达式转换为后缀表达式
for(int i=0; i<str.length();){
if(str[i]>='0' && str[i]<='9'){
string num;
while(i<str.length() && str[i]>='0' && str[i]<='9'){
num+=str[i];
i++;
}
q.push(num);
}else{
string op;
op=str[i];
while(!s.empty() && mp[op]<=mp[s.top()]){
q.push(s.top());
s.pop();
}
s.push(op);
i++;
}
}
while(!s.empty()){
q.push(s.top());
s.pop();
}
}
double stringToDouble(string s){
stringstream ss;
ss.precision(12);
ss<<s;
double d;
ss>>d;
return d;
}
string doubleTostring(double s){
stringstream ss;
ss.precision(12);
//精度设置,如果不设置,对于
30 / 90 - 26 + 97 - 5 - 6 - 13 / 88 * 6 + 51 / 29 + 79 * 87 + 57 * 92 最后一位出现错误。
ss<<s;
string d;
ss>>d;
return d;
}
double cal(){
double temp1, temp2;
string cur;
while(!q.empty()){
cur=q.front();
q.pop();
if(isdigit(cur[0])) s.push(cur);
else{
temp2=stringToDouble(s.top());
s.pop();
temp1=stringToDouble(s.top());
s.pop();
double temp;
if(cur=="+") temp=temp1+temp2;
else if(cur=="-") temp=temp1-temp2;
else if(cur=="*") temp=temp1*temp2;
else temp=temp1/temp2;
s.push(doubleTostring(temp)); //这里尝试过用to_string()
}
}
return stringToDouble(s.top());
}
int main(){
mp["+"]=0;mp["-"]=0;
mp["*"]=1;mp["/"]=1;
while(getline(cin, str), str!="0"){
for(string::iterator it=str.begin(); it!=str.end(); it++){
if(*it==' ') str.erase(it);
}
while(!s.empty()) s.pop();
change();
printf("%.2f\n", cal());
}
return 0;
}
AC:
#include<iostream>
#include<string>
#include<stack>
#include<fstream>
#include<queue>
#include<map>
using namespace std;
#include<sstream>
struct node{
double num;
char op;
bool flag;
};
string str; //中缀表达式
stack<node> s; //操作符栈
queue<node> q; //后缀表达式序列
map<char, int> op; //操作符和优先级的映射
void change(){ //将中缀表达式转换为后缀表达式
node temp;
for(int i=0; i<str.length();){
if(str[i]>='0' && str[i]<='9'){
temp.flag=true;
temp.num=str[i++]-'0';
while(i<str.length() && str[i]>='0' && str[i]<='9'){
temp.num=temp.num*10+(str[i]-'0');
i++;
}
q.push(temp);
} else{
temp.flag=false;
while(!s.empty() && op[str[i]]<=op[s.top().op]){
q.push(s.top());
s.pop();
}
temp.op=str[i];
s.push(temp);
i++;
}
}
while(!s.empty()){
q.push(s.top());
s.pop();
}
}
double cal(){
double temp1, temp2;
node cur, temp;
while(!q.empty()){
cur=q.front();
q.pop();
if(cur.flag==true) s.push(cur);
else{
temp2=s.top().num;
s.pop();
temp1=s.top().num;
s.pop();
temp.flag=true;
if(cur.op=='+') temp.num=temp1+temp2;
else if(cur.op=='-') temp.num=temp1-temp2;
else if(cur.op=='*') temp.num=temp1*temp2;
else temp.num=temp1/temp2;
s.push(temp);
}
}
return s.top().num;
}
string doubleTostring(double s){
stringstream ss;
ss<<s;
string d;
ss>>d;
return d;
}
int main(){
op['+']=op['-']=1;
op['*']=op['/']=2;
while(getline(cin, str), str!="0"){
for(string::iterator it=str.begin(); it!=str.end(); it++){
if(*it==' ') str.erase(it);
}
while(!s.empty()) s.pop();
change();
printf("%.2f\n", cal());
}
return 0;
}
上面两种代码都是按照同一个思路来的,改动就是栈的类型。
WA的代码所有的类型都视为string,当需要的时候,就利用stringstream进行类型转换,个人感觉就是这里出了点错误。
可能是类型转换中的精度问题,多次转换后的值出现了变换,但是自己没有找到能证明错误的数据,就先记录在这里了。