日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

信息学奥赛一本通 1962:【13NOIP普及组】表达式求值 | 洛谷 P1981 [NOIP2013 普及组] 表达式求值

發布時間:2025/3/17 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 信息学奥赛一本通 1962:【13NOIP普及组】表达式求值 | 洛谷 P1981 [NOIP2013 普及组] 表达式求值 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【題目鏈接】

ybt 1962:【13NOIP普及組】表達式求值
洛谷 P1981 [NOIP2013 普及組] 表達式求值

【題目考點】

  • 中綴表達式轉后綴表達式,后綴表達式求值
  • 中綴表達式求值
  • 【解題思路】

    表達式中只有加法和乘法,數字是0~231?10 \sim 2^{31}-10231?1,運算中不會出現負數。由于最后只需要最后4位,即結果%10000的值。根據同余定理:
    (a+b)%m=(a%m+b%m)%m(a+b)\%m = (a\%m+b\%m)\%m(a+b)%m=(a%m+b%m)%m(a?b)%m=((a%m)?(b%m))%m(a*b)\%m = ((a\%m)*(b\%m))\%m(a?b)%m=((a%m)?(b%m))%m
    運算時,將每個數字都%10000,每次計算后的結果都%10000,最終得到的結果就是真實結果%10000后的值。
    具體解法有兩種

  • 先將中綴表達式轉為后綴表達式,而后求后綴表達式的值
  • 直接求中綴表達式的值
  • 【題解代碼】

    解法1:先將中綴表達式轉為后綴表達式,而后求后綴表達式的值

    中綴表達式轉后綴表達式方法:

  • 從左向右掃描表達式字符串。
  • 遇到數字時,直接輸出。
  • 遇到運算符時,如果棧空,或該運算符優先級大于棧頂運算符優先級,則入棧。否則運算符出棧并輸出。重復這一過程。
  • 掃描結束后若棧中有運算符,都出棧并輸出。
  • 后綴表達式求值:

  • 從左向右掃描字符串
  • 遇到數字時,將數字入棧。
  • 遇到運算符時,彈出棧頂的兩個數,用該運算符對它們做相應的計算,結果入棧。
  • 掃描結束后,棧頂數字就是結果。
  • 本題解中,用一個數組e表示后綴表達式,數組中元素e[i]若大于等于0,表示數字。若e[i]為-1,表示乘號,若e[i]為-2,表示加號。這里乘號的值大于加號的值,可以表示乘號的優先級大于加號。

    運算符最多10510^5105個,那么運算符與數字加起來不會超過3?1053*10^53?105個,所以數組大小開為3?1053*10^53?105

    #include <bits/stdc++.h> using namespace std; #define N 100000 #define M 10000 #define ADD -2 //加號 #define MULT -1//乘號 int e[3*N], e_i;//保存后綴表達式,e[i]若大于等于0,表示數字。若e[i]為-1,表示乘號,若e[i]為-2,表示加號。e_i:e數組待添加元素的位置 int stk[2*N], top; int main() {char c;int num = 0, cVal, a, b;//cVal:運算符的值:加號為-2,乘號為-1; a,b:運算數c = getchar();//輸入并構建后綴表達式while(c != EOF && c != '\n')//不確定OJ輸入的末尾是文件末尾EOF,還是換行符'\n',所以二者都可能是輸入的結束符號,都判斷一下。{if(c >= '0' && c <= '9')//c是數字num = (num * 10 + c - '0') % M;else//c是運算符{e[e_i++] = num;//后綴表達式添加numnum = 0;if(c == '+')cVal = ADD;//如果是加號elsecVal = MULT;//如果是乘號while(!(top == 0 || cVal > stk[top]))//如果棧中有運算符,且運算符c比棧頂運算符的優先級相等或更低,則運算符出棧,輸出到后綴表達式e[e_i++] = stk[top--];stk[++top] = cVal;//此時運算符入棧}c = getchar();}e[e_i++] = num;//添加最后一個數字while(top > 0)//將棧中剩余的運算符加入后綴表達式e[e_i++] = stk[top--];//此時后綴表達式構建完成,開始根據后綴表達式求值for(int i = 0; i < e_i; ++i){if(e[i] >= 0)//如果是數字stk[++top] = e[i];//數字入棧else//如果是運算符{a = stk[top--];//數字出棧b = stk[top--];//數字出棧if(e[i] == ADD)//如果是加號stk[++top] = (a + b) % M;//計算結果入棧else//如果是乘號stk[++top] = (a * b) % M;//計算結果入棧}}cout<<stk[top];//棧頂數值即為運算結果return 0; }

    解法2:直接求中綴表達式的值

    中綴表達式求值:

  • 設數字棧,運算符棧。從左向右掃描表達式
  • 遇到數字進數字棧
  • 遇到運算符,如果運算符棧棧空,或該運算符優先級大于棧頂運算符優先級,則入棧。否則運算符出棧,從數字棧出棧2個數字,進行計算,結果在數字棧入棧。重復這一過程。
  • 掃描結束后,運算符棧出棧運算符,進行運算,直到運算符棧為空。最后數字棧棧頂的數字,就是結果。
  • #include<bits/stdc++.h> using namespace std; #define N 100005 #define M 10000 int nStk[N], nTop, cTop;//nStk:數字棧 nTop:數字棧棧頂位置 cTop:運算符棧棧頂位置 char cStk[N];//cStk:運算符棧 int main() {char c, tc;//c:讀入的字符 tc:出棧的字符int num = 0, a, b;c = getchar();while(c != EOF && c != '\n'){if(c >= '0' && c <= '9')//如果遇到數字字符num = (num * 10 + c - '0') % M;else//如果遇到運算符{nStk[++nTop] = num;num = 0;while(!(cTop == 0 || c == '*' && cStk[cTop] == '+'))//棧空或要入棧的運算符比棧頂運算符優先級高,才可以入棧,其他情況都出棧,做運算。{a = nStk[nTop--];//數字棧出棧兩個數b = nStk[nTop--];tc = cStk[cTop--];//運算符棧出棧一個運算符,if(tc == '*')//進行計算,結果存入數字棧nStk[++nTop] = (a * b) % M;elsenStk[++nTop] = (a + b) % M;}cStk[++cTop] = c;}c = getchar();}nStk[++nTop] = num;//添加最后一個數字while(cTop > 0)//如果運算符棧還有運算符,運算符出棧,運算,直到棧空為止{a = nStk[nTop--];//數字棧出棧兩個數b = nStk[nTop--];tc = cStk[cTop--];//運算符棧出棧一個運算符,if(tc == '*')//進行計算,結果存入數字棧nStk[++nTop] = (a * b) % M;elsenStk[++nTop] = (a + b) % M;}cout<<nStk[nTop];//數字棧棧頂即為結果return 0; }

    同樣解法,使用string讀入,使用c++ stl的stack類來做

    #include<bits/stdc++.h> using namespace std; #define N 100005 #define M 10000 stack<int> nStk;//nStk:數字棧 stack<char> cStk;//cStk:運算符棧 string s; int main() {char c;int num = 0, a, b;cin>>s;for(int i = 0; i < s.length(); ++i){if(s[i] >= '0' && s[i] <= '9')num = (num * 10 + s[i] - '0') % M;else{nStk.push(num);num = 0;while(!(cStk.empty() || s[i] == '*' && cStk.top() == '+')){b = nStk.top(); nStk.pop();a = nStk.top(); nStk.pop();c = cStk.top(); cStk.pop();if(c == '*')nStk.push(a * b % M);elsenStk.push((a + b) % M);}cStk.push(s[i]);}}nStk.push(num);//最后的數字入棧 while(cStk.empty() == false)//其余運算符出棧,運算 {b = nStk.top(); nStk.pop();a = nStk.top(); nStk.pop();c = cStk.top(); cStk.pop();if(c == '*')nStk.push(a * b % M);elsenStk.push((a + b) % M);}cout<<nStk.top();fclose(stdin);return 0; } 新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!

    總結

    以上是生活随笔為你收集整理的信息学奥赛一本通 1962:【13NOIP普及组】表达式求值 | 洛谷 P1981 [NOIP2013 普及组] 表达式求值的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。