1. 程式人生 > >【NOIP2013普及組P2】表示式求值(NKOJ2500)題解

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