洛谷P1575正误问题

题目地址https://www.luogu.com.cn/problem/P1575

题意:给出一个字符串,其中只有true、false、and、not、or这五种字符,其中运算符的优先级是not>and>or,输出最后表达式的结果true或者false。当然,如果表达式本身就是一个错误的表达式(例如true and and false),则输出error

输入:一行字符数据

输出:预期结果

题解:只要学过数据机构这本书,那么对于这道题的思路都不会有什么大的问题。对于这种题,我想最合适的解决方法就是利用栈来解决。首先设立两个栈:操作符栈、数值栈。顾名思义就是一个存储操作符,一个存储数值。当遍历到一个数值(在这里也就是true和false)时,就将这个数据存储到数值栈中去,如果是操作符x,首先看操作符栈是否为空,为空,则将操作符x放入操作符栈,否则将x与操作符栈的栈顶元素y进行比较。如果x>=y,则直接将x放入操作符栈,如果y>x(操作符之间都是指的优先级的大小关系),则取出栈顶操作符进行运算,然后删除栈顶操作符,再观察此时的栈顶元素与x的优先级,直到操作符栈为空或者栈顶元素的优先级小于等于x。然后就这样遍历整个表达式,最后再对操作符栈从栈顶元素开始遍历执行(因为当遍历完整个表达式后,操作符栈一定不为空,但是注意此时操作符栈中的元素从栈顶开始到栈底元素的优先级肯定是非递增的,所以可以从栈顶直接向栈底遍历执行操作符)。最后数值栈中剩余的元素就是最后的结果。当然需要注意的是,上面的的叙述都是建立在表达式是一个正确的表达式,并不是一个不可以被正确执行的表达式,如果不是一个正确的表达式,可以在遍历表达式的过程中就可以发现,而且不算什么难的点。

AC代码

#include<iostream>
#include<stack> 
using namespace std;
stack<int>op;//not:3,and:2,or:1
stack<int>va;//true:1,false:0
int plug=0;
int value(char str[]){
    if(str[0]=='f') return 0;
    else return 1;
}
void make_or_and(){//执行or或者and操作 
    if(va.size()<2) {//如果数值栈的元素个数小于2,那么就是一个错误的表达式 
        plug=1;
        return ;
    }
    int x=va.top();va.pop();
    int y=va.top();va.pop();
    //对栈顶元素进行and或者or操作 
    if(op.top()==1) va.push((x||y));
    else va.push((x&&y));
}
void make_not(){//执行非not操作 
    if(va.size()<1){//如果数值栈的元素小于1,那么此时表达式就是一个错误的表达式 
        plug=1;//错误表达式标志 
        return ;
    }
    //对数值栈的栈顶元素进行not操作 
    int x=va.top();va.pop();
    va.push((!x));
}
void make(char str[]){
    int p;
    switch(str[0]){//首先确定当前操作符的优先级 
        case 'n':p=3;break;
        case 'a':p=2;break;
        case 'o':p=1;break;
    }
    if(op.empty()||p>=op.top()){//如果操作符栈为空或者p的优先级大于等于当前栈顶元素的优先级时 
        op.push(p);
        return ;
    }
    while(!op.empty()&&op.top()>p){//当操作符栈为非空并且当前栈顶元素的优先级大于p 
        switch(op.top()){//对不同的栈顶的操作符实行不同的表达式运算 
            case 1: case 2: make_or_and();break;
            case 3:make_not();break;
        }
        op.pop();//之前这一行忘记写了,很多测试点一直TLE,让我以为自己的复杂度很高,结果纠结了好长时间(⊙﹏⊙) 
    }
    op.push(p);
}
int main(){
    char str[10];
    while(cin>>str){
        switch(str[0]){
            case 'f': case 't':va.push(value(str));break;
            case 'n': case 'a': case 'o':make(str);break;
        }
    }
    while(!op.empty()){//遍历完表达式之后,对操作符栈从栈顶开始遍历执行操作 
        switch(op.top()){
        case 1: case 2: make_or_and();break;
        case 3:make_not();break;
        }
        op.pop();
    }
    if(plug||va.size()>1) cout<<"error";//之前忘记va.size()<1,结果有一个测试点过不去(⊙﹏⊙) 
    else if(va.top()==1) cout<<"true";
         else cout<<"false";    
    return 0;
}

写于2020/8/6 1:42


作者:孙建钊
出处:http://www.cnblogs.com/sunjianzhao/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文地址:https://www.cnblogs.com/sunjianzhao/p/13443850.html