sjtu-acm-1033

5 篇文章 1 订阅
5 篇文章 0 订阅

想了想,似乎有必要把自己刷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 Token
class 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





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值