1. 程式人生 > 實用技巧 >洛谷P1981《表示式求值》

洛谷P1981《表示式求值》

原更新日期:2018-10-06 21:28:34

新技能:手寫計算器

題目描述

給定一個只包含加法和乘法的算術表示式,請你程式設計計算表示式的值。

Input / Output 格式 & 樣例

輸入格式

一行,為需要你計算的表示式,表示式中只包含數字、加法運算子“\(+\)”和乘法運算子“ \(\times\) ”,且沒有括號,所有參與運算的數字均為 \(0\)\(2^{31}\)的整數。

輸入資料保證這一行只有 \(0−9\)\(+\)\(\times\)\(12\) 種字元。

輸出格式

一個整數,表示這個表示式的值。

注意:當答案長度多於 4 位時,請只輸出最後 4 位,前導 0 不輸出。

輸入樣例

Case #1:

1+1*3+4

Case #2:

1+1234567890*1

Case #3:

1+1000000003*1

輸出樣例

Case #1:

8

Case #2:

7891

Case #3:

4

資料範圍

對於 30%的資料,0≤表示式中加法運算子和乘法運算子的總數≤100;

對於 80%的資料,0≤表示式中加法運算子和乘法運算子的總數≤1000;

對於100%的資料,0≤表示式中加法運算子和乘法運算子的總數≤100000。

解題思路

我們開兩個單調棧,一個棧num來儲存數字,一個棧operators來儲存符號

其中operators的操作邏輯是這樣的:

  • 首先把~push進去,作為一個佔位符
  • 我們對運算子標一個優先順序,規定~ < + < *
    且相同運算子優先順序低(滿足從左到右的運算順序),寫一個判斷函式
  • 當push進去的運算子優先順序比棧頂的低時,解決所有優先順序低的運算子(維護單調性質)再push進去
  • 當push進去的運算子優先順序比棧頂的高時,不用管,直接push進去(滿足單調性質)

處理完輸入之後,我們再對數字棧裡剩下的數字進行處理

最後輸出即可

程式碼實現

這裡面所有的註釋都是我在DEBUG的時候手推的樣例

/* -- Basic Headers -- */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>

/* -- STL Iterators -- */
#include <vector>
#include <string>
#include <stack>
#include <queue>

/* -- External Headers -- */

/* -- Defined Functions -- */
#define For(a,x,y) for (int a = x; a <= y; ++a)
#define Forw(a,x,y) for (int a = x; a < y; ++a)
#define Bak(a,y,x) for (int a = y; a >= x; --a)

/* -- Defined Words -- */

using namespace std;

namespace FastIO {
    void DEBUG(char comment[], int x) {
        cerr << comment << x << endl;
    }

    inline int getint() {
        int s = 0, x = 1;
        char ch = getchar();
        while (!isdigit(ch)) {
            if (ch == '-') x = -1;
            ch = getchar();
        }
        while (isdigit(ch)) {
            s = s * 10 + ch - '0';
            ch = getchar();
        }
        return s * x;
    }
    inline void __basic_putint(int x) {
        if (x < 0) {
            x = -x;
            putchar('-');
        }
        if (x >= 10) __basic_putint(x / 10);
        putchar(x % 10 + '0');
    }

    inline void putint(int x, char external) {
        __basic_putint(x);
        putchar(external);
    }
}

namespace Solution {
    stack<int> num;
    stack<int> operators;
    // 1: + -
    // 2: * /
    
    const int MOD = 10000;
    long long int ans = 0;
    
    bool Priority(char op1, char op2) {
        // false -> op1 is lower
        // true -> op1 is higher
        if (op1 == op2) return false;
        if (op1 == '~') return false;
        if (op1 == '+' && op2 == '*') return false;
        if (op1 == '*' && op2 == '+') return true;
    }
}

int main(int argc, char *const argv[]) {
    #ifdef HANDWER_FILE
    freopen("testdata.in", "r", stdin);
    freopen("testdata.out", "w", stdout);
    #endif
    using namespace Solution;
    using namespace FastIO;
    // 1+1*3+4
    int ans = 0, now = 0;
    char op = 0;
    cin >> ans; // 1
    num.push(ans % MOD); // < 1
    operators.push('~'); // < ~
    while (cin >> op >> now) { // +1 // *3 // +4
        char op1 = operators.top(); // ~ // + // *
        while (Priority(op1, op)) { // false // false // true // false
            int opNum = num.top(); // // // 3
            num.pop(); // // //  < 1 1
            int opNum2 = num.top(); // // // 1
            num.pop(); // // // < 1 
            if (op1 == '+') num.push((opNum + opNum2) % MOD); // // // false
            if (op1 == '*') num.push(opNum * opNum2 % MOD); // // // < 1 3
            operators.pop(); // < +
            op1 = operators.top(); // +
        }
        operators.push(op); // < + // < + * // < + +
        num.push(now); // < 1 1 // < 1 1 3 // < 1 3 4
    }
    while (num.size() > 1) { // true // true // false
    	int op = num.top(); // 4 // 7
    	num.pop(); // < 1 3 // < 1
    	int op2 = num.top(); // 3 // 1
    	num.pop(); // < 1 // <
    	char ope = operators.top();
    	operators.pop();
        if (ope == '+') num.push((op + op2) % MOD); // < 1 7 // < 8
        if (ope == '*') num.push(op * op2 % MOD);
    }
    FastIO::putint(num.top() % MOD, '\n'); // 8
    return 0;
}