sjtu-acm-1033

来源:互联网 发布:淘宝客是做什么的 编辑:程序博客网 时间:2024/06/09 13:46

想了想,似乎有必要把自己刷OJ的历程记录下来。

不光光是为了总结报告和以后积累经验。

http://acm.sjtu.edu.cn/OnlineJudge/

上海交大的OJ网址。

-----------------------------------------------------------------------------我是华丽的分割线--------------------------------------------------------------------------------------------------------------------------------------

Description

二哥想自己做一个计算器,但是他需要一个程序来计算输入表达式的结果。你能帮助他吗?

Input Format

输入仅一行,给出一个算数表达式。表达式中包含:小括号,加减乘除,指数运算符,负号,整数,空格。其中负号的优先级最高(-),其次是指数运算(^),然后是乘除(*/),最后是加减(+-)。

这里规定除法为整除运算,如 5 / 2 = 2, 8 / -3 = -2 等等,与C++中的整除一致。另外注意指数运算为右结合,即 2^3^2 = 2^9 = 512 而非 2^3^2 = 8^2 = 64 。

输入的字符串长度不超过100。

Output Format

如果输入的表达式出现括号不匹配或者除零错误,输出一行“Error”(不含引号),否则输出运算结果。输入保证不包含任何其它类型的错误。

输入的数,输出的答案,以及中间结果均保证是不超过 long long 范围的整数。

一道计算器题。

有两种实现的思路。

1.文法树。

2.逆波兰表达式。

一开始我用的文法树的方式来实现。发现无论文法树还是逆波兰表达式效率其实都差不多。(显然文法树蛋疼很多很多)

但一直没搞明白关于逆波兰表达式的负号和减号的预处理。

参见:http://blog.csdn.net/jxsfreedom/article/details/4978189  最后评论里面没说清楚。。。

我用的primary,cache,term,expression 分别处理各个优先级。

代码:

//文法的规则了。#include <iostream>#include <cstdlib>//#include <string>#include<math.h>using namespace std;long long expression();long long cache();long long term();long long primary();void calculator();void _exp(long long & x, long long y);const char number = '3';    // t.kind==number means that t is a number Tokenclass Token{public:char kind;long long value;Token(char ch):kind(ch){}Token(char ch, long long v):kind(ch),value(v){}};class Token_stream{public:Token_stream():full(false),buffer(0){}Token get();void putback(Token);private:bool full;Token buffer;}ts;void Token_stream::putback(Token t){full = true;buffer = t;}Token Token_stream::get(){if(full){full = false;return buffer;}char ch;ch=cin.get();while (ch == ' ')ch = cin.get();switch(ch){case '\n':    case '(':    case ')':    case '+':    case '-':    case '*':    case '/': case '^':return Token(ch);case '0': case '1': case '2': case '3': case '4':    case '5': case '6': case '7': case '8': case '9':    // numeric literal{}}}void calculator(){cout<< expression() << endl;}long long expression(){long long left = term();//cout << "expre 1 : " << left << endl;Token t = ts.get();while(1)  {switch(t.kind){case '+':t = ts.get();break;case '-':left -= term();t = ts.get();break;default:{if( t.kind == ')' || t.kind == '\n' ){//cout << "expre 2 : " << left << endl;return left;}else {cout << "Error" << endl;exit(0);}}}}}long long term(){long long left = cache();//cout << "term1 left is:" << left << endl;while(1){switch(t.kind){case '*' :left *= cache();t = ts.get();break;case '/':{long long denominator = cache();left /= denominator;t = ts.get();break;}default:ts.putback(t);//cout << "term2 left is:" << left << endl;return left;}}}long long cache(){long long left = primary();//cout << "!!!" << endl;Token t = ts.get();//cout << t.kind << "asfafa" << endl;switch (t.kind){case'^'://cout << "cache1 left is:" << left << endl;return left;default:ts.putback(t);//cout << "cache2 left is:" << left << endl;return left;}}long long primary(){Token t = ts.get();switch(t.kind){case number:{//cout << "pri left is:" << t.value << endl;return t.value;}case '(':{long long val = expression();t = ts.get();if (t.kind != ')') {cout << "Error" << endl;exit(0);}return val;}case '+':return primary();default:cout << "Error" << endl;exit(0);}}void _exp(long long & x, long long y){if (y == 0) x = 1;if (x == 1) return;if (x == 0)return;long long r = 1, base = x;while (y != 0){if (y & 1)r *= base;base *= base;y >>= 1;}x = r;}int main(){calculator();    //cin.get();return 0;}

//为防止抄袭,代码有些部分被我删掉了。但大体框架还是可以看得很清楚的。需要源码的联系我。


值得一提的是,cache与其他东西不太一样,原因在于cache对应的符号^的优先级和其他符号略微有些不同。一般来说,+-*/都是顺序执行的。即:1+3+4,1*2*4,1/2/3都是按从左至右的顺序来执行。

而3^5^2是按照从右至左来执行。所以只能用递归了。

不管怎么说,总体设计还是挺精妙的。

最后交了好几次TLE了好几次。原因求幂算法复杂度太高。

换了快速幂就ac了.

http://baike.baidu.com/link?url=xJdOFxcQ4-QrCB_UN8BCbJjcp0nNZYVgeEdLia4uYXmN0N9HppLR3ZhpIaPJH17DF2TXodyupr7joUsX84GRca





0 0
原创粉丝点击