码迷,mamicode.com
首页 > 其他好文 > 详细

P1054 等价表达式

时间:2020-09-02 16:44:55      阅读:52      评论:0      收藏:0      [点我收藏+]

标签:中间   介绍   work   main   printf   cst   math   数字   tin   

题意描述

等价表达式

给出一个表达式,求之后给出的与之等价的表达式。

保证每个表达式最多只有一个变量 \(a\),可能有 +,-,*,(,),^ 运算。

算法分析

思路

由于只有一个变量,我们可以将 \(a\) 特殊值化,如果最终结果相同那么判定两式等价。

为了减小误差,我们可以多取几个值,但是由于有乘方操作所以最好不要太大。

之后就是中缀表达式的计算,我采用的方法是中缀转后缀再求值,具体方法下文介绍。

有了这个思路就可以开始实现了。

输入

采用 cinscanf 输入都会有点问题,因为中间可能有对于空格。

所以这里采用 getchar 写一个类似快读函数来输入。

string read(){
    string sum;
    char c=getchar();
    while(c==‘\n‘ || c==‘\r‘) c=getchar();//在 windows 和 Linux 下的换行符分别是 \n 和 \r。
    while((c>=‘0‘ && c<=‘9‘) || c==‘a‘ || c==‘+‘ || c==‘-‘ || c==‘*‘ || c==‘/‘ || c==‘^‘ || c==‘(‘ || c==‘)‘ || c==‘ ‘){
        if(c!=‘ ‘) sum+=c;
        c=getchar();
    }
    return sum;
}

中缀转后缀

考虑建立一个符号栈,进行一下操作:

  1. 遇到一个数字或 \(a\) 直接输出。
  2. 遇到左括号,入栈。
  3. 遇到右括号,不断取出栈顶并输出,直到栈顶为左括号,然后左括号出栈。
  4. 遇到运算法,只要栈顶符号的优先级不低于新符号,就不断取出栈顶并输出。
  5. 结束后输出栈中所有剩余符号。

但是这个题目毒瘤还有括号不匹配的情况可能会直接导致 RE,所以需要特判。

为了方便统计数字,防止类似 4+1+2 -> 41+2+ 导致 4,1 两个数字变为 41 的情况发生,加上 .

stack<char>st;
int n=s.length();

string change(){
    string a;
    for(int i=0;i<n;i++){
        if((s[i]>=‘0‘ && s[i]<=‘9‘) || s[i]==‘a‘) {a+=s[i];continue;}//遇到一个数字或 a 直接输出。
        a+=‘.‘;//加点。
        if(s[i]==‘(‘) st.push(s[i]);//遇到左括号,入栈。
        else if(s[i]==‘)‘){//遇到右括号,不断取出栈顶并输出,直到栈顶为左括号,然后左括号出栈。
            while(!st.empty() && st.top()!=‘(‘){
                a+=st.top();st.pop();
            }
            if(st.empty()) return "ppp";//特判。
            st.pop();
        }//遇到运算法,只要 栈顶符号的优先级不低于新符号,就不断取出栈顶并输出。
        else if(s[i]==‘+‘ || s[i]==‘-‘){
            while(!st.empty() && (st.top()==‘+‘ || st.top()==‘-‘ || st.top()==‘*‘ || st.top()==‘/‘ || st.top()==‘^‘)){
                a+=st.top();st.pop();
            }
        }
        else if(s[i]==‘*‘ || s[i]==‘/‘){
            while(!st.empty() && (st.top()==‘*‘ || st.top()==‘/‘ || st.top()==‘^‘)){
                a+=st.top();st.pop();
            }
        }
        else if(s[i]==‘^‘){
            while(!st.empty() && (st.top()==‘^‘)){
                a+=st.top();st.pop();
            }
        }
        if(s[i]!=‘(‘ && s[i]!=‘)‘) st.push(s[i]);
    }
    a+=‘.‘;//加点。
    while(!st.empty()) {a+=st.top();st.pop();}//结束后输出栈中所有剩余符号。
    return a;
}

后缀表达式求值

用一个栈模拟即可,不再赘述。

stack<int>sa;

int count(string a,int aa){
    int len=a.length(),i=0,sum=0;
    bool flag=false;
    for(int i=0;i<len;i++){
        if(a[i]>=‘0‘ && a[i]<=‘9‘) {sum=sum*10+a[i]-‘0‘;flag=true;}//记录数字。
        else if(a[i]==‘.‘) {if(flag) sa.push(sum);sum=0;flag=false;}//加点的妙用。
        else if(a[i]==‘a‘) sa.push(aa);//给 a 赋特殊值。
        else if(a[i]==‘+‘){
            int q=sa.top();sa.pop();
            int p=sa.top();sa.pop();
            sa.push(p+q);
        }
        else if(a[i]==‘-‘){
            int q=sa.top();sa.pop();
            int p=sa.top();sa.pop();
            sa.push(p-q);
        }
        else if(a[i]==‘*‘){
            int q=sa.top();sa.pop();
            int p=sa.top();sa.pop();
            sa.push(p*q);
        }
        else if(a[i]==‘/‘){
            int q=sa.top();sa.pop();
            int p=sa.top();sa.pop();
            sa.push(p/q);
        }
        else if(a[i]==‘^‘){
            int q=sa.top();sa.pop();
            int p=sa.top();sa.pop();
            sa.push(Pow(p,q));
        }
    }
    return sa.top();
}

注意

虽然题目中说指数不可能大于 10,但是会有这种情况发生 a^10^10^10

所以为了避免溢出,应当采用较小的 a 值并用 long long 进行记录。

代码实现

前文介绍的很清楚了,其实不需要整块的代码介绍,不过还是扔在这里吧。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<stack>
#define N 6000
#define M 1000
#define int long long
using namespace std;

int n,m;
int ans[M],now[M];
string s;
stack<char>st;
stack<int>sa;

string read(){
    string sum;
    char c=getchar();
    while(c==‘\n‘ || c==‘\r‘) c=getchar();
    while((c>=‘0‘ && c<=‘9‘) || c==‘a‘ || c==‘+‘ || c==‘-‘ || c==‘*‘ || c==‘/‘ || c==‘^‘ || c==‘(‘ || c==‘)‘ || c==‘ ‘){
        if(c!=‘ ‘) sum+=c;
        c=getchar();
    }
    return sum;
}

string change(){
    string a;
    for(int i=0;i<n;i++){
        if((s[i]>=‘0‘ && s[i]<=‘9‘) || s[i]==‘a‘) {a+=s[i];continue;}
        a+=‘.‘;
        if(s[i]==‘(‘) st.push(s[i]);
        else if(s[i]==‘)‘){
            while(!st.empty() && st.top()!=‘(‘){
                a+=st.top();st.pop();
            }
            if(st.empty()) return "ppp";
            st.pop();
        }
        else if(s[i]==‘+‘ || s[i]==‘-‘){
            while(!st.empty() && (st.top()==‘+‘ || st.top()==‘-‘ || st.top()==‘*‘ || st.top()==‘/‘ || st.top()==‘^‘)){
                a+=st.top();st.pop();
            }
        }
        else if(s[i]==‘*‘ || s[i]==‘/‘){
            while(!st.empty() && (st.top()==‘*‘ || st.top()==‘/‘ || st.top()==‘^‘)){
                a+=st.top();st.pop();
            }
        }
        else if(s[i]==‘^‘){
            while(!st.empty() && (st.top()==‘^‘)){
                a+=st.top();st.pop();
            }
        }
        if(s[i]!=‘(‘ && s[i]!=‘)‘) st.push(s[i]);
    }
    a+=‘.‘;
    while(!st.empty()) {a+=st.top();st.pop();}
    return a;
}

int Pow(int a,int b){
    int sum=1;
    while(b){if(b&1) sum*=a;a*=a;b>>=1;}
    return sum;
}

int count(string a,int aa){
    int len=a.length(),i=0,sum=0;
    bool flag=false;
    for(int i=0;i<len;i++){
        if(a[i]>=‘0‘ && a[i]<=‘9‘) {sum=sum*10+a[i]-‘0‘;flag=true;}
        else if(a[i]==‘.‘) {if(flag) sa.push(sum);sum=0;flag=false;}
        else if(a[i]==‘a‘) sa.push(aa);
        else if(a[i]==‘+‘){
            int q=sa.top();sa.pop();
            int p=sa.top();sa.pop();
            sa.push(p+q);
        }
        else if(a[i]==‘-‘){
            int q=sa.top();sa.pop();
            int p=sa.top();sa.pop();
            sa.push(p-q);
        }
        else if(a[i]==‘*‘){
            int q=sa.top();sa.pop();
            int p=sa.top();sa.pop();
            sa.push(p*q);
        }
        else if(a[i]==‘/‘){
            int q=sa.top();sa.pop();
            int p=sa.top();sa.pop();
            sa.push(p/q);
        }
        else if(a[i]==‘^‘){
            int q=sa.top();sa.pop();
            int p=sa.top();sa.pop();
            sa.push(Pow(p,q));
        }
    }
    return sa.top();
}

void work(bool flag){
    s=read();
    n=s.length();
    string a=change();
    if(a=="ppp") return;
    for(int i=1;i<=5;i++){
        if(flag) ans[i]=count(a,i);
        else now[i]=count(a,i);
    }
    return;
}

bool cmp(){
    for(int i=1;i<=5;i++)
        if(now[i]!=ans[i]) return false;
    return true;
}

signed main(){
    work(1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        work(0);
        if(cmp()) printf("%c",‘A‘+i-1);
    }
    return 0;
}

完结撒?。

P1054 等价表达式

标签:中间   介绍   work   main   printf   cst   math   数字   tin   

原文地址:https://www.cnblogs.com/lpf-666/p/13529052.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!