【NOIP2013普及组P2】表达式求值(NKOJ2500)题解

【NOIP2013普及组P2】表达式求值

Time Limit:10000MS  Memory Limit:128000K
Total Submit:37 Accepted:19
Case Time Limit:1000MS

Description

给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

Input

输入仅有一行,为需要你计算的表达式,表达式中只包含数字、加法运算符“+”和乘法运算符“*”,且没有括号.
所有参与运算的数字均为0到2^31-1之间的整数。输入数据保证这一行只有0~9、+、*这12种字符。

Output

输出只有一行,包含一个整数,表示这个表达式的值。注意:当答案长度多于4位时,请只输出最后4位,前导0不输出。

Sample Input

【样例1】
1+1*3+4
【样例2】
1+1234567890*1
【样例3】
1+1000000003*1

Sample Output

【样例1】
8
【样例2】
7891
【样例3】
4

Hint

【样例说明】
样例1计算的结果为8,直接输出8。
样例2计算的结果为1234567891,输出后4位,即7891。
样例3计算的结果为1000000004,输出后4位,即4。

【数据范围】
对于30%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100;
对于80%的数据,0≤表达式中加法运算符和乘法运算符的总数≤1000;
对于100%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100000。

Source

中缀表达式求值——用两个栈 sign[] 和 num[] 分别存储符号和数字。


当读入的字符是数字的时候:

用 tt 表示当前读到的单个数字,则 number = number * 10 + tt

当读入的字符是符号的时候:

1.此时可以保证之前读入的一个完整数字 number 已经可以放入 num 栈当中了, 即 num[++topn] =number ;并将 number 赋值为 0 ,便于下次正确读入一个完整数字;

2.

a.)如果当前读到的运算符优先级低于或等于前一个(即 sign 栈顶)运算符优先级,则前面读到的两个数 (num[topn - 1] 和 num[topn])可以进行运算,并把运算后的结果直接替代到 num[topn - 1] ——举个例 子,对于这个式子 3 * 2 + 1 ,当读入到加号的时候便可以把式子从 3 * 2 + 变化为 6 + 了;

b.)如果当前读入的运算符优先级大于之前读入的运算符,则正常压入符号栈 sign 当中;


请注意,当我们这样完整地一边读入一边处理完一个式子之后,此时的简化后的式子一定满足:前面的运算符优先级小于等于后面(即运算符升序排列)——这是因为如果读入时一个式子优先级大于等于后面的运算符,则已经被提前计算并化简成一个数字,比如 3 * 2 + 1 ,在读入加号时便把 3 * 2 化为 6 了。

既然此时的式子满足这样一个顺序(运算符升序排列),我们只要从后往前把式子算一遍就可以得出表达式的值了。

写到这里,程序框架已经很清晰了;当然,针对于题目而言自然有一些相应的细节。比如,这道题当中只要求输出最后 4 位,所以运算过程当中是可以随时取模 10000(=10^4) 的(实际上也需要这么做,因为尽管每个数不会超过 2^31 - 1 ,但它们的积或和就不一定了,是很有可能爆 long long int 的)。


最后附上代码。

#include 
long long int num[100005];
char sign[100005], temp[4];
int lv[100005], signlv[260];
int topn, tops;
long long int number;
long long int f(char s) {
	switch (s) {
	case '+':
		return (num[topn] + num[topn + 1]) % 10000;
	case '*':
		return (num[topn] * num[topn + 1]) % 10000;
	default:
		return -1;
	}
	return -1;
}
void init() {
	lv[0] = -1;
	signlv['+'] = 1;
	signlv['*'] = 2;
	return ;
}
void solve() {
	char tt;
	while ((tt = getchar()) != '\n') {
		switch (tt) {
		case '+':
		case '*': {
			num[++topn] = number;
			number = 0;
			if (lv[tops] < signlv[tt])
				++tops;
			else
				num[--topn] = f(sign[tops]);
			sign[tops] = tt;
			lv[tops] = signlv[tt];
			break;
		}
		default: {
			number = number * 10 + tt - '0';
			break;
		}
		}
	}
	num[++topn]= number;
	while (tops)
		num[--topn] = f(sign[tops--]);
	return ;
}
void output() {
	bool flag = false;
	temp[0] = num[1] % 10;
	temp[1] = (num[1] /= 10) % 10;
	temp[2] = (num[1] /= 10) % 10;
	temp[3] = (num[1] /= 10) % 10;
	if (!temp[0] && !temp[1] && !temp[2] && !temp[3]) {
		putchar('0');
		putchar('\n');
		return ;
	}
	if (temp[3] || flag) {
		putchar(temp[3] + '0');
		flag = true;
	}
	if (temp[2] || flag) {
		putchar(temp[2] + '0');
		flag = true;
	}
	if (temp[1] || flag) {
		putchar(temp[1] + '0');
		flag = true;
	}
	if (temp[0] || flag)
		putchar(temp[0] + '0');
	putchar('\n');
	return ;
}
int main() {
	init();
	solve();
	output();
	return 0;
}

你可能感兴趣的:(题解)