Openjudge 等价表达式

目录

等价表达式

要求:

描述:

输入:

输出:

样例输入:

样例输出:

思路分析:

最终代码:


等价表达式

要求:

总时间限制: 1000ms

内存限制: 65536kB

描述:

判断两个表达式在数学上是否是等价的。 

输入:

第一行:N(1<=N<=20),表示测试数据组数。
接下来每组测试数据包括两行,每行包括一个数学表达式,每个表达式的长度不超过80个字符。输入数据没有空行。

一个表达式可能包括:
单个英文字母表示的变量(区分大小写)
数字(只有一位数)
配对的括号
运算符加+、减-、乘*
任意数量的空格或tab(可能出现在表达式中间的任何位置)

注意:表达式保证是语法正确的,且所有运算符的优先级相同,运算次序从左至右。变量的系数和指数保证不超过16位整数。

输出:

 对每个测试数据,输出一行:等价则输出“YES”,不等价则输出“NO”。

样例输入:

3
(a+b-c)*2
(a+a)+(b*2)-(3*c)+c
a*2-(a+c)+((a+c+e)*2)
3*a+c+(2*e)
(a-b)*(a-b)
(a*a)-(2*a*b)-(b*b)

样例输出:

YES
YES
NO

思路分析:

 这个题目的思路还是比较新颖的:如果我们想要直接进行表达式的变化,类似数学变换来考察两个式子是否等价是很难的,即使这种方法本身是充要完备的.

那么一个替代性的不太完备的方法就是模拟. 通过代入一些数据并进行计算,看看两式运算结果是否相同,这一条件并非两式等价的充要条件,而只是必要条件,所以实际上并不完备,但却能极大减低我们编程以及程序运行的复杂度. 所以模拟在一定程度上是一种折衷.

这样的话,此题就被大幅度简化了,剩下的只需要处理中缀表达式的运算即可,这一点利用栈的LIFO特性就可以实现(虽然有点复杂),如果不了解可以先看一下数据结构与算法的相关内容.

最终代码:

我们利用srand(time(0))rand()来生成随机数,从而赋给式子中的字母变量;再利用unordered_map来实现变量对应值的存储,关于unordered_map的应用可以看我以前的帖子.

#include<iostream>
#include<stack>
#include<unordered_map>
#include<ctime>
using namespace std;
void operate(stack<char>& stk1, stack<int>& stk2){
    char ch=stk1.top();
    int x1=stk2.top(); stk2.pop();
    int x2=stk2.top(); stk2.pop();
    stk1.pop();
    switch(ch){
    case '*':
        stk2.push(x1*x2);
        break;
    case '+':
        stk2.push(x1+x2);
        break;
    case '-':
        stk2.push(x2-x1);
        break;
    }
}
int main(){
    int N;
    scanf("%d",&N);getchar();
    stack<char> stk1;
    stack<int> stk2;
    unordered_map<char,int> mm;
    srand(time(0));
    int ans[2];
    while(N--){
        string str;
        for(int k=0;k<2;k++){
            getline(cin,str);
            int len = str.size();
            for(int i=0;i<len;i++){
                switch(str[i]){
                    case ')':
                        while(stk1.top()!='(')
                            operate(stk1, stk2);
                        stk1.pop();
                        break;
                    case '(':
                        stk1.push(str[i]);
                        break;
                    case '*':
                        stk1.push(str[i]);
                        break;
                    case '+':
                        while(!stk1.empty()&&stk1.top()!='(')
                            operate(stk1, stk2); 
                        stk1.push(str[i]);
                        break;
                    case '-':
                        while(!stk1.empty()&&stk1.top()!='(')
                            operate(stk1, stk2); 
                        stk1.push(str[i]);
                        break;
                    case ' ':
                        continue;
                    case '\t':
                        continue;
                    default:
                        if(isalpha(str[i])){//如果是字母
                            mm.insert(pair<char,int>(str[i],(rand()%10)+1));
                            stk2.push(mm[str[i]]);
                        }
                        /*如果是数字*/
                        else if(isdigit(str[i])) stk2.push(str[i]-'0');
                }
            }
            while(!stk1.empty()) 
                operate(stk1, stk2);
            ans[k]=stk2.top();
            str.clear();
            stk2.pop();
        }
        if(ans[0]==ans[1]) printf("YES\n");
        else printf("NO\n");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值