【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;
}