[Codevs 1107][NOIP 1107]等价表达式

题目连接:http://codevs.cn/problem/1107/

一道很神奇的题目。对于算术表达式一类的问题,可以采用编译原理里的后缀表达式的方式来做,具体做法是分别维护两个栈,一个栈里保存表达式里的数字,另一个栈里保存表达式里的运算符,给每种运算符一个优先级,我们要维护这个栈的单调性,每次读入运算符中的数字或运算符,读入的是运算符时,若这个运算符比栈顶的运算符优先级低,就弹出栈顶元素,把栈顶的运算符和数字栈里栈顶的两个数字拿出来做一次运算,运算结果再入数字栈,直到运算符栈的栈顶元素优先级比这个运算符低为止。

然后题目有坑点,一是读入的表达式字符串可能有空格,所以不能直接scanf一次搞定读入数据操作。二是判断表达式是否等价时,带入的值如果不好可能会WA,所以为了避免这种情况的发生,我们代入的数字应该是个小数,用三态函数判断表达式结果是否相等,多代入几个小数计算,基本上不可能出现意外WA的发生。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <map>
#include <cmath>

#define MAXN 1000
#define EPS (1e-5)

using namespace std;

long long stackOfNum[MAXN];
int topNum=0; //保存数字的栈和栈顶下标
char stackOfSign[MAXN];
int topSign=0; //保存运算符号的栈和栈顶下标
bool needPop[50][50]; //needPop[i][j]=true表示当前运算符为i,栈顶运算符为j时需要出栈
bool isTrue[30];

int dcmp(long long a,long long b) //a>b return 1; a=b return 0; a<b return -1
{
    if(fabs(a-b)<=EPS)
        return 0;
    if(a>b)
        return 1;
    return -1;
}

long long cal(long long a,long long b,char cmd)
{
    switch(cmd)
    {
        case '^':
        {
            long long ans=1;
            for(int i=1;i<=(int)b;i++)
                ans*=a;
            return ans;
        }
        case '+': return a+b;
        case '-': return a-b;
        case '*': return a*b;
        case '/': return a/b;
    }
    return 0;
}

long long getAns(char s[],int len,long long a) //将表达式的值求出来,len=表达式长度,a=字母a对应的值
{
    int p=1; //指针指向当前的表达式下标
    topNum=0;
    topSign=0;
    while(p<=len)
    {
		while(s[p]==' ') p++;
		if(p>len) break;
        if(s[p]>='0'&&s[p]<='9') //是数字
        {
            int nowNum=0;
            while(p<=len)
            {
                if(!(s[p]>='0'&&s[p]<='9')) //现在的s[p]不是数字了
                    break;
                nowNum*=10;
                nowNum+=s[p]-'0';
                p++;
            }
            stackOfNum[++topNum]=nowNum; //这个数字进栈
            continue;
        }
        else if(s[p]=='a')
            stackOfNum[++topNum]=a; //如果是a,将a对应的数字压入栈
        else //s[p]是个运算符,将栈中所有比它优先级
        {
            while(topSign>0&&topNum>0)
            {
                if(needPop[s[p]][stackOfSign[topSign]])
                {
                    if(stackOfSign[topSign]=='(') //右括号遇到左括号
                    {
                        topSign--;
                        break;
                    }
                    stackOfNum[topNum-1]=cal(stackOfNum[topNum-1],stackOfNum[topNum],stackOfSign[topSign]);
                    topNum--;
                    topSign--;
                }
                else break;
            }
            if(s[p]!=')') stackOfSign[++topSign]=s[p];
        }
        p++;
    }
    while(topSign>0&&topNum>1)
    {
        stackOfNum[topNum-1]=cal(stackOfNum[topNum-1],stackOfNum[topNum],stackOfSign[topSign]);
        topNum--;
        topSign--;
    }
    return stackOfNum[topNum];
}

int main()
{
    memset(isTrue,true,sizeof(isTrue));
    //先打个巨表~!
    needPop['^']['^']=true;
    needPop['^']['+']=false;
    needPop['^']['-']=false;
    needPop['^']['*']=false;
    needPop['^']['/']=false;
    needPop['^']['(']=false;
    //----------------------
    needPop['+']['^']=true;
    needPop['+']['+']=true;
    needPop['+']['-']=true;
    needPop['+']['*']=true;
    needPop['+']['/']=true;
    needPop['+']['(']=false;
    //----------------------
    needPop['-']['^']=true;
    needPop['-']['+']=true;
    needPop['-']['-']=true;
    needPop['-']['*']=true;
    needPop['-']['/']=true;
    needPop['-']['(']=false;
    //----------------------
    needPop['*']['^']=true;
    needPop['*']['+']=false;
    needPop['*']['-']=false;
    needPop['*']['*']=true;
    needPop['*']['/']=true;
    needPop['*']['(']=false;
    //----------------------
    needPop['/']['^']=true;
    needPop['/']['+']=false;
    needPop['/']['-']=false;
    needPop['/']['*']=true;
    needPop['/']['/']=true;
    needPop['/']['(']=false;
    //----------------------
    needPop['(']['^']=false;
    needPop['(']['+']=false;
    needPop['(']['-']=false;
    needPop['(']['*']=false;
    needPop['(']['/']=false;
    needPop['(']['(']=false;
    //----------------------
    needPop[')']['^']=true;
    needPop[')']['+']=true;
    needPop[')']['-']=true;
    needPop[')']['*']=true;
    needPop[')']['/']=true;
    needPop[')']['(']=true;
    char s[MAXN];
    int n;
    long long trueAns1,trueAns2,nowAns1,nowAns2; //trueAns=带入a值后应该得到的答案,nowAns=选择选项中带入a值得到的答案
    //scanf("%s",s+1);
	gets(s+1);
    trueAns1=getAns(s,strlen(s+1),1.4);
    trueAns2=getAns(s,strlen(s+1),2.8);
    scanf("%d",&n);
	gets(s+1);
    for(int i=0;i<n;i++)
    {
        //scanf("%s",s+1);
		gets(s+1);
		nowAns1=getAns(s,strlen(s+1),1.4);
		nowAns2=getAns(s,strlen(s+1),2.8);
        if(dcmp(trueAns1,nowAns1)!=0) //trueans==nowans
            isTrue[i]=false;
        if(dcmp(trueAns2,nowAns2)!=0) //trueans==nowans
            isTrue[i]=false;
    }
    for(int i=0;i<n;i++)
        if(isTrue[i])
            printf("%c",'A'+i);
    printf("\n");
    return 0;
}
时间: 2024-10-10 18:20:03

[Codevs 1107][NOIP 1107]等价表达式的相关文章

[Codevs 1107][NOIP 1107]等效表达

主题连接:http://codevs.cn/problem/1107/ 一道非常奇妙的题目. 对于算术表达式一类的问题,能够採用编译原理里的后缀表达式的方式来做.详细做法是分别维护两个栈,一个栈里保存表达式里的数字,还有一个栈里保存表达式里的运算符,给每种运算符一个优先级,我们要维护这个栈的单调性,每次读入运算符中的数字或运算符,读入的是运算符时,若这个运算符比栈顶的运算符优先级低,就弹出栈顶元素.把栈顶的运算符和数字栈里栈顶的两个数字拿出来做一次运算,运算结果再入数字栈.直到运算符栈的栈顶元素

数据结构--栈 codevs 1107 等价表达式

codevs 1107 等价表达式 2005年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的. 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这

1107 等价表达式

1107 等价表达式 2005年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的. 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来

等价表达式

栈的经典题目,开两个栈,一个存符号,一个存数字: 分情况讨论: 1.如果当前读到的运算符优先级小于栈顶,就进行一次运算,直到大于等于: 2.如果读到数字用类似读入优化的方法读入进来: 3.如果当前符号为"("则直接入栈: 4.如果当前符号为")"则进行运算直到碰到"(": 5.小技巧 在式子开头加"(",末尾加")": 6.遇到a,让a等于质数: 7.多次取模,因为有可能爆long long,模不同的质数,

和指针相关的两个特殊运算符,和相关的等价表达式

和指针相关的两个特殊运算符: 一."&" 取地址运算符,通过&运算符可以取出普通变量的地址: 二."*"  有两种意义: 1.  为指针标志: 是否为指针标志主要看前面是否有类型,此处有一个int 2.  为指针运算符:    在等号右面为取值.*可以取出指针变量所指向的普通变量的值.   在等号左面为赋值.*可以将指针变量所指向的普通变量的值,修改为其他. 3.  为乘法运算符.当且仅当左右的都为变量时.略. 如 int a, b =20, c=3

NOIP2005 等价表达式 解题报告

明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的. 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题.假设你是明明,能完成这个任务吗? 这个选择题中的每个表达式都满足下面的性质: 1.  表达式只可能包含一个变量‘a’. 2.  表达式中出现的数都是正整数,而且都小于10000. 3.

等价表达式(noip2005)

3.等价表达式 [问题描述]    兵兵班的同学都喜欢数学这一科目,中秋聚会这天,数学课代表给大家出了个有关代数表达式的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的.    这个题目手算很麻烦,因为数学课代表对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题.假设你是数学课代表,能完成这个任务吗? 这个选择题中的每个表达式都满足下面的性质: 1. 表达式只可能包含一个变量

等价表达式(codevs 1107 答案错误)

题目描述 Description 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的. 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题.假设你是明明,能完成这个任务吗? 这个选择题中的每个表达式都满足下面的性质:1.表达式只可能包含一个变量‘a’.2.表达式中出现的数都是正整数,而且都

等价表达式 (codevs 1107)题解

[问题描述] 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的. 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题.假设你是明明,能完成这个任务吗? 这个选择题中的每个表达式都满足下面的性质:1.表达式只可能包含一个变量‘a’.2.表达式中出现的数都是正整数,而且都小于10000.3.