1 条题解

  • 0
    @ 2026-10-27 4:21:39

    思路与算法

    原题称逆波兰,但示例明确运算符在前,应按前缀表达式求值。流式读入记号,运算符压入一个待计算栈帧;读到数值后,若顶帧尚缺左操作数就保存它,否则按左、右的顺序计算并弹帧,把结果继续交给外层。最终得到根值,以固定6位小数输出。

    正确性说明

    前缀表达式的一个运算符后面恰有左右两个完整子表达式。栈帧表示当前已读入但尚未完成的运算符,has标记是否已有完整左值。一个数或子表达式结束时,向上一帧交付其值:第一份成为左值,第二份与左值计算后完成此帧。按表达式树结构归纳,每次弹出的值正是对应子树的值,最后空栈时得到整个表达式的值。显式栈同时避免深表达式递归溢出。

    复杂度

    O(t+字符总数)时间、O(h)额外空间,t为记号数,h为同时未完成的运算符层数;包括动态栈初始化与记号数值解析。没有把原题未给的表达式长度改成固定数组容量。

    易错点

    减除法左右操作数顺序不能交换;-2.5是一个数值,不是独立减号。按题面printf(%f)示意使用double和6位小数。只对有意义的合法算术表达式求值,不能把它当成运算符在后的后缀式。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    struct Frame {
        char op;
        bool has;
        double left;
    };
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        vector<Frame> stack;
        string token;
        double answer = 0;
        while (cin >> token) {
            if (token == "+" || token == "-" || token == "*" || token == "/") {
                stack.push_back({token[0], false, 0});
                continue;
            }
            double value = stod(token);
            while (!stack.empty()) {
                auto &f = stack.back();
                if (!f.has) {
                    f.has = true;
                    f.left = value;
                    break;
                }
                double a = f.left;
                char op = f.op;
                stack.pop_back();
                if (op == '+')
                    value = a + value;
                else if (op == '-')
                    value = a - value;
                else if (op == '*')
                    value = a * value;
                else
                    value = a / value;
            }
            if (stack.empty())
                answer = value;
        }
        cout << fixed << setprecision(6) << answer << "\n";
    }
    
    • 1

    信息

    ID
    1991
    时间
    1000ms
    内存
    64MiB
    难度
    进阶
    标签
    递交数
    0
    已通过
    0
    上传者