zoukankan      html  css  js  c++  java
  • 1033. 表达式求值

    Description

    二哥想自己做一个计算器,但是他需要一个程序来计算输入表达式的结果。你能帮助他吗?

    Input Format

    输入仅一行,给出一个算数表达式。表达式中包含:小括号,加减乘除,指数运算符,负号,整数,空格。其中负号的优先级最高(-),其次是指数运算(^),然后是乘除(*/),最后是加减(+-)。

    这里规定除法为整除运算,如 5 / 2 = 2, 8 / -3 = -2 等等,与C++中的整除一致。另外注意指数运算为右结合,即 2^3^2 = 2^9 = 512 而非 2^3^2 = 8^2 = 64 。

    输入的字符串长度不超过100。

    Output Format

    如果输入的表达式出现括号不匹配或者除零错误,输出一行“Error”(不含引号),否则输出运算结果。输入保证不包含任何其它类型的错误。

    输入的数,输出的答案,以及中间结果均保证是不超过 long long 范围的整数。

    Sample Input

    5 + (1 + 3) * 6 ^ 1
    

    Sample Output

    29
    

    Sample Input

    (6 + 2)) * 3
    

    Sample Output

    Error
    

    说明

    30%的测试数据含有负号;

    30%的测试数据含有指数运算。

    #include <iostream>
    #include <memory>
    #include <stack>
    #include <fstream>
    #include <vector>
    #include <cmath>
    #include <iomanip>
    #include <exception>
    #include <climits>
    #include <array>
    #include <cstdint>
    
    
    
    using namespace std;
    
    class Token {
    public:
        virtual bool isOperator()=0;
        virtual ~Token() {}
    };
    
    class ValueToken : public Token {
    public:
        long long value;
        long long get_value(){ return value;}
        virtual bool isOperator() { return false; }
        explicit ValueToken(long long val) : value(val) {}
    };
    
    class OperatorToken : public Token {
    public:
        enum OpType {
            BGN=0, END, ADD, MNS, NEG, MUL, DIV, POW, LBK, RBK
        } optr;
    
        virtual bool isOperator() { return true; }
        char get_char(){
            switch (optr){
                case BGN:
                    return '@';
                case END:
                    return '$';
                case ADD:
                    return '+';
                case MNS:
                    return '-';
                case NEG:
                    return '#';
                case MUL:
                    return '*';
                case DIV:
                    return '/';
                case POW:
                    return '^';
                case LBK:
                    return '(';
                case RBK:
                    return ')';
                default:
                    return '?';
            }
        }
        explicit OperatorToken(OperatorToken::OpType op) : optr(op) {}
        bool is_prior(const OperatorToken& r){
            return prior_table[this->optr][r.optr];
        }
        static bool prior_table[10][10];
    };
    bool OperatorToken::prior_table[10][10]={
            //BGN, END, ADD, MNS, NEG, MUL, DIV, POW, LBK, RBK
            {0,0,0,0,0,0,0,0,0,0},//BGN
            {1,0,0,0,0,0,0,0,0,0},//END
            {1,1,0,0,0,0,0,0,1,0},//ADD
            {1,1,0,0,0,0,0,0,1,0},//MNS
            {1,1,1,1,0,1,1,1,1,0},//NEG
            {1,1,1,1,0,0,0,0,1,0},//MUL
            {1,1,1,1,0,0,0,0,1,0},//DIV
            {1,1,1,1,0,1,1,1,1,0},//POW
            {1,1,1,1,1,1,1,1,1,0},//LBK
            {1,1,0,0,0,0,0,0,1,0},//RBK
    };
    
    vector<shared_ptr<Token>> pre_process(const string &str) {
        vector<shared_ptr<Token>> ret;
        ret.emplace_back(new OperatorToken(OperatorToken::BGN));
        long long val = 0;
        bool f = false, is_neg = true;
        for (char c:str) {
            if (c >= '0' && c <= '9') {
                if (f)val = val * 10 + c - '0';
                else val = c - '0';
                is_neg= false;
                f = true;
            } else {
                if (f) {
                    ret.emplace_back(new ValueToken(val));
                }
                switch (c) {
                    case '+':
                        ret.emplace_back(new OperatorToken(OperatorToken::ADD));
                        is_neg=true;
                        break;
                    case '-':
                        ret.emplace_back(new OperatorToken(is_neg?OperatorToken::NEG:OperatorToken::MNS));
                        is_neg=true;
                        break;
                    case '*':
                        ret.emplace_back(new OperatorToken(OperatorToken::MUL));
                        is_neg=true;
                        break;
                    case '/':
                        ret.emplace_back(new OperatorToken(OperatorToken::DIV));
                        is_neg=true;
                        break;
                    case '^':
                        ret.emplace_back(new OperatorToken(OperatorToken::POW));
                        is_neg=true;
                        break;
                    case '(':
                        ret.emplace_back(new OperatorToken(OperatorToken::LBK));
                        is_neg=true;
                        break;
                    case ')':
                        ret.emplace_back(new OperatorToken(OperatorToken::RBK));
                        is_neg= false;
                        break;
                    case ' ':
                        break;
                    default:
                        break;
                }
                val = 0;
                f = false;
            }
        }
        if(f)ret.emplace_back(new ValueToken(val));
        ret.emplace_back(new OperatorToken(OperatorToken::END));
        return ret;
    }
    
    void print(const vector<shared_ptr<Token>> v){
        for(auto p:v){
            if(p->isOperator()){
                cout<<static_pointer_cast<OperatorToken>(p)->get_char();
            }
            else{
                cout<<static_pointer_cast<ValueToken>(p)->get_value();
            }
        }
    }
    
    void compute(stack<shared_ptr<OperatorToken>>& optrs, stack<long long>& vals){
        long long l,r,s;
        auto op=optrs.top()->optr;
        optrs.pop();
        switch (op){
            case OperatorToken::ADD:
                if(vals.size()<2)throw exception();
                r=vals.top();
                vals.pop();
                l=vals.top();
                vals.pop();
                vals.push(l+r);
    #ifdef DEBUG
                cout<<l<<"+"<<r<<"="<<vals.top()<<endl;
    #endif
                break;
            case OperatorToken::MNS:
                if(vals.size()<2)throw exception();
                r=vals.top();
                vals.pop();
                l=vals.top();
                vals.pop();
                vals.push(l-r);
    #ifdef DEBUG
                cout<<l<<"-"<<r<<"="<<vals.top()<<endl;
    #endif
                break;
            case OperatorToken::NEG:
                if(vals.size()<1)throw exception();
                l=vals.top();
                vals.pop();
                vals.push(-l);
    #ifdef DEBUG
                cout<<" neg "<<l<<"="<<vals.top()<<endl;
    #endif
                break;
            case OperatorToken::MUL:
                if(vals.size()<2)throw exception();
                r=vals.top();
                vals.pop();
                l=vals.top();
                vals.pop();
                vals.push(l*r);
    #ifdef DEBUG
                cout<<l<<"*"<<r<<"="<<vals.top()<<endl;
    #endif
                break;
            case OperatorToken::DIV:
                if(vals.size()<2)throw exception();
                r=vals.top();
                vals.pop();
                if(!r)throw exception();
                l=vals.top();
                vals.pop();
                vals.push(l/r);
    #ifdef DEBUG
                cout<<l<<"/"<<r<<"="<<vals.top()<<endl;
    #endif
                break;
            case OperatorToken::POW:
                if(vals.size()<2)throw exception();
                r=vals.top();
                vals.pop();
                l=vals.top();
                vals.pop();
                s=pow(l,r);
                vals.push(s);
    #ifdef DEBUG
                cout<<l<<"^"<<r<<"="<<vals.top()<<endl;
    #endif
                break;
            case OperatorToken::RBK:
                if(optrs.top()->optr!=OperatorToken::LBK)throw exception();
                optrs.pop();
    #ifdef DEBUG
                cout<<"()"<<endl;
    #endif
                break;
            case OperatorToken::END:
                optrs.pop();
                break;
    
            default:
                throw exception();
                break;
        }
    }
    
    int main() {
    
        string string1;
        getline(cin,string1);
        auto s = pre_process(string1);
        stack<shared_ptr<OperatorToken>> optrs;
        stack<long long> vals;
        optrs.push(dynamic_pointer_cast<OperatorToken>(s[0]));
        try{
            for(auto& ptoken:s){
                if(ptoken==s[0])continue;
                if(!ptoken->isOperator())vals.push(dynamic_pointer_cast<ValueToken>(ptoken)->value);
                else{
                    shared_ptr<OperatorToken> ptr=dynamic_pointer_cast<OperatorToken>(ptoken);
                    while (!ptr->is_prior(*optrs.top())){
                        compute(optrs,vals);
                    }
                    optrs.push(ptr);
                }
            }
            if(vals.size()!=1||optrs.size()!=2)throw exception();
        }catch (exception e){
            cout<<"Error";
            return 0;
        }
        cout<<vals.top();
        return 0;
    }

     
     

  • 相关阅读:
    二分图最大匹配的K&#246;nig定理及其证明
    HDOJ 2389 Rain on your Parade
    HDOJ 1083 Courses
    HDOJ 2063 过山车
    POJ 1469 COURSES
    UESTC 1817 Complete Building the Houses
    POJ 3464 ACM Computer Factory
    POJ 1459 Power Network
    HDOJ 1532 Drainage Ditches
    HDU 1017 A Mathematical Curiosity
  • 原文地址:https://www.cnblogs.com/bernieloveslife/p/7978160.html
Copyright © 2011-2022 走看看