[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-11-01 21:49:35

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

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

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

[CODEVS 1043] Noip 2000 方格取数

1043 方格取数 时间限制: 1s  空间限制: 128000 KB 题目描述 Description 设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.如下图所示(见样例): 某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点.在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0). 此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大. 输入描述 Input Description 输入的

X-003 FriendlyARM tiny4412 uboot移植之添加相应目录文件

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

C语言学习笔记---谭浩强

前段时间有机会去面试了一次,真是备受“打击”(其实是启发),总的来说就是让我意识到了学习工具和学习技术的区别.所以最近在看一些数据结构和算法,操作系统,python中的并行编程与异步编程等东西.然而数据结构那些本来是在看python下的,但是python实在包装了太多的东西而大多的经典教材都是基于C语言的(自然是这样,C语言能够操作直接访问物理地址,能够进行位(bit)操作的特点就决定了.)所以就决定重新学一遍C语言,先重温下谭浩强老师的书籍记录下要点: 一:语言: 机器语言:计算机直接识别和接

使用curl操作openstack swift

openstack官网有专门的开发者文档介绍如何使用curl操作swift(http://docs.openstack.org/api/openstack-object-storage/1.0/content/),本文做了些翻译工作并在自己创建的swift集群中做了实验,如果希望阅读完整的swift开发者文档,请到官网阅读,内容还是很详细的,本文只是向希望了解swift对象存储的朋友做个直观的展示. 1. Curl Curl是一个命令行工具,能够通过命令行发送和接受http请求和响应,这使得它能

在ros-kinetic与gazebo仿真环境下给turtlebot配置hokuyo激光雷达

背景 由于我之前按照百度上博客教程给gazebo上的turtlebot配置rplidar的时候一直失败,后来发现是因为在ros-indigo和kinetic下的一些差异导致配置失败,于是又搜了一些教程成功配置了hokuyo的激光雷达,并且能够较完美地运行,感觉比较激动,所以想写个教程避免自己以后再次踩坑. 准备 安装好ros-turtlebot以及ros-turtlebot-apps,可以选择源码安装或者apt安装 增加hokuyo模块 ( 如果是使用apt安装的apps,首先需要  sudo

Bisecting GlcNAc is a general suppressor of terminal modification of N-glycan (解读人:王茹凯)

文献名:Bisecting GlcNAc is a general suppressor of terminal modification of N-glycan(平分GlcNAc是N-聚糖末端修饰的一般抑制剂) 期刊名:MCP 发表时间:(2019年10月) 单位: 广岛大学物质科学研究科 爱尔兰国立大学糖业科学小组 RIKEN-Max Planck联合研究中心结构糖生物学小组 物种:小鼠大脑组织.肾组织 技术:转染.蛋白印迹.凝集素印迹.免疫荧光.定量PCR.糖基转移酶化验.LC-MS\MS

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

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

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

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