当前位置: 首页 > news >正文

UVa 354 Crazy Calculator

题目描述

ACM\texttt{ACM}ACM行星的东南部,存在多种使用非标准运算符符号的方言。这些方言中,加、减、乘、整数除法这四种运算分别使用不同的本地符号,且它们的优先级(数字越大优先级越高)和结合性(L左结合,R右结合)也各不相同。

给定一个方言描述(包含四个标准运算符对应的本地符号、优先级和结合性),以及若干条使用该方言书写的表达式,要求计算每个表达式的值,并将表达式中的本地运算符替换为标准运算符(+-*/)后输出。

输入格式

(注意:在线测试数据的格式与题目描述不符,以下是经过测试得到的正确的在线测试数据格式)

输入文件包含多组测试数据(组数由第一行整数TTT给出)。每组数据格式如下:

  • 第一行为一个空行(仅在组间存在,第一组前也有一个空行)。
  • 接下来444行,每行是一个长度为444的字符串c1c2c3c4c_1c_2c_3c_4c1c2c3c4,描述一个标准运算符的本地映射:
    • c1c_1c1:标准运算符(+-*/之一);
    • c2c_2c2:该运算符对应的本地符号(一个可见字符,不含数字、括号及空白);
    • c3c_3c3:一个数字字符(0~9),表示该运算符的优先级;
    • c4c_4c4:一个字母,L表示左结合,R表示右结合。
  • 之后若干行,每行一个使用本地符号书写的表达式(不含空白字符),表达式可包含数字、括号以及上述四个本地符号。表达式以空行结束(即下一行为空行),表示该组数据结束。

输入以EOF\texttt{EOF}EOF结束。

输出格式

对于每个输入表达式,输出一行,内容为:将本地运算符替换为标准运算符后的表达式,后跟一个空格、一个等号、一个空格,以及该表达式的计算结果。每组内的表达式连续输出,组间由一个空行分隔。

样例

输入

2 +@1L -#3R *$2L /%2L 1@2#3 (1@2)#3 3@4#5$6 +*1L -&2L *#3R /$4L 1*2*3 1&2#3*4 10$3*2

输出

1+2-3 = 0 (1+2)-3 = 0 3+4-5*6 = -3 1+2+3 = 6 1-2*3+4 = -1 10/3+2 = 5

题目分析

本题的核心是实现一个能够处理自定义优先级和结合性的表达式求值器。与常规算术表达式不同,这里运算符的优先级(数字0∼90 \sim 909)和结合性(左/右)由输入动态指定,且必须严格遵循:

  • 相同运算符重复时,按其自身结合性(左或右)进行结合。
  • 不同运算符(即使优先级相同)一律按从左到右的顺序执行。

这意味着我们不能使用标准的中缀转后缀算法(如调度场算法),因为调度场算法通常预设同优先级运算符具有相同的结合性(例如+-都是左结合),而本题中不同运算符可能拥有不同的结合性,但同优先级不同运算符之间却强制左结合。

同时,表达式可能包含括号,需要正确处理括号内的子表达式。

解题思路

递归下降解析器

我们采用优先级爬升(Pratt Parser\texttt{Pratt Parser}Pratt Parser的递归下降解析方法。定义一个解析函数parseExpr(minPrec),它解析一个表达式,其中minPrec表示当前允许的最低优先级。函数返回一个Node结构,包含表达式的计算结果val以及对应的标准运算符表达式字符串stdExpr

解析过程如下:

  1. 解析基本单元parsePrimary):

    • 若当前字符为(,则递归调用parseExpr(0)解析括号内的内容,遇到)后结束,返回内部节点的值。
    • 否则,读取连续的数字字符,返回其整数值。
  2. 处理运算符

    • parseExpr中,先获得左部表达式left
    • 然后循环检查当前字符是否为已定义的本地运算符。若是,则获取其优先级prec和结合性assoc
    • 根据结合性决定是否停止结合当前运算符:
      • 若为左结合(L),当prec < minPrec时停止;
      • 若为右结合(R),当prec <= minPrec时停止。
    • 如果不需要停止,则消费该运算符,递归解析右部表达式,传入的minPrec为:
      • 左结合时传prec + 1
      • 右结合时传prec
    • 然后计算左部和右部结果,生成标准表达式字符串,更新left为新节点。

该算法通过调整递归调用时的minPrec参数,有效地控制了运算符的结合顺序:左结合运算符要求右侧表达式的优先级必须大于当前优先级(即prec+1),从而保证同优先级的运算符不会被右侧吸收;右结合运算符则允许右侧表达式包含相同优先级的运算符(即prec),从而形成右结合。

输出

每个Node在计算过程中同时生成对应的标准表达式字符串,合并左右子表达式和当前标准运算符,最终根节点的stdExpr即为转换后的完整表达式。

正确性说明

  • 递归下降解析器严格按照优先级和结合性规则构造语法树,每次结合运算符时都正确限制了右侧子表达式的优先级范围。
  • 括号通过parsePrimary中的递归调用优先处理,符合括号最高优先级的惯例。
  • 最终生成的表达式字符串与计算结果一致。

复杂度分析

设表达式长度为LLL。递归下降解析过程中,每个字符至多被访问一次(数字可能连续读取),因此单次表达式求值的时间复杂度为O(L)O(L)O(L)。空间复杂度为递归调用栈深度,最坏情况下为O(L)O(L)O(L)(深层嵌套括号),可接受。

对于多组测试数据,总时间复杂度为O(∑L)O(\sum L)O(L),其中∑L\sum LL为所有表达式长度之和。

代码实现

由于在线测试数据的输出可能存在问题,导致本题难以通过。

// Crazy Calculator// UVa ID: 354// Verdict: Wrong Answer// Submission Date: 2026-06-21// UVa Run Time: 0.070s//// 版权所有(C)2026,邱秋。metaphysis # yeah dot net#include<bits/stdc++.h>usingnamespacestd;unordered_map<char,char>localToStd;// 本地符号 -> 标准运算符unordered_map<char,int>localPrec;// 本地符号 -> 优先级unordered_map<char,char>localAssoc;// 本地符号 -> 结合性structNode{intval;string stdExpr;};// 函数原型声明intapplyOp(inta,intb,charstdOp);NodeparsePrimary();NodeparseExpr(intminPrec);string expr;intpos,n;intapplyOp(inta,intb,charstdOp){switch(stdOp){case'+':returna+b;case'-':returna-b;case'*':returna*b;case'/':return(b==0)?0:a/b;}return0;}NodeparsePrimary(){if(pos<n&&expr[pos]=='('){++pos;// 跳过 '('Node inner=parseExpr(0);if(pos<n&&expr[pos]==')')++pos;return{inner.val,"("+inner.stdExpr+")"};}else{intnum=0;while(pos<n&&isdigit(expr[pos])){num=num*10+(expr[pos]-'0');++pos;}return{num,to_string(num)};}}NodeparseExpr(intminPrec){Node left=parsePrimary();while(pos<n&&localToStd.find(expr[pos])!=localToStd.end()){charop=expr[pos];intprec=localPrec[op];charassoc=localAssoc[op];if((assoc=='L'&&prec<minPrec)||(assoc=='R'&&prec<=minPrec))break;++pos;// 消费运算符Node right=parseExpr((assoc=='L')?prec+1:prec);intres=applyOp(left.val,right.val,localToStd[op]);string stdExpr=left.stdExpr+localToStd[op]+right.stdExpr;left={res,stdExpr};}returnleft;}intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);string line;getline(cin,line);intT=stoi(line);getline(cin,line);// 空行for(intcs=0;cs<T;++cs){if(cs)cout<<'\n';localToStd.clear();localPrec.clear();localAssoc.clear();for(intk=0;k<4;++k){getline(cin,line);charstdOp=line[0];charlocalSym=line[1];intprec=line[2]-'0';charassoc=line[3];localToStd[localSym]=stdOp;localPrec[localSym]=prec;localAssoc[localSym]=assoc;}while(getline(cin,line)){if(line.empty())break;expr=line;pos=0;n=expr.size();Node root=parseExpr(0);cout<<root.stdExpr<<" = "<<root.val<<'\n';}}return0;}
http://www.jsqmd.com/news/1060803/

相关文章:

  • 大模型性能测试:vLLM部署下的显存带宽与CUDA Stream瓶颈分析
  • 旧手机别再吃灰了:我用转转上门回收把抽屉清空,顺手摸透了一套不扯皮回收的标准 - 热点速览
  • Seedance 2.0:音视频节奏对齐的多模态生成技术栈
  • 真茶屋加盟官方渠道权威说明 - 热点速览
  • 如何快速免费解锁Wand专业版:终极游戏修改工具WandEnhancer完整指南
  • 速存!2026 年 6 月欧米茄官方维修门店最新地址全发布,全新全国统一售后热线同步上线 - 欧米茄中国服务中心
  • 2026年武汉科谷技工学校招生简章(官方咨询发布) - 武汉中职最新信息发布
  • 2026PDF转Word保姆级教程:手机+电脑免费方法,在线、本地工具一看就会 - 软件小管家
  • 一文讲透供应链核心10个系统(附架构图):SCM, SRM, WMS, TMS, ERP, PLM, MES, PMS, ...
  • 体验家 XMPlus 房地产行业客户体验管理:从看房到交付的全触点数字化实践
  • 集成电路展会哪家展会最具行业影响力?2026年集成电路展会推荐 - 品牌深度评测
  • 爱回收报价透明吗?从一机一况定价到价保规则的完整拆解 - 资讯焦点
  • DeepSeek V4 MoE大模型技术解析与昇腾910C本地部署指南
  • 混元3.0技术解析:大模型工程化落地的确定性架构
  • 计算机毕业设计之jsp古诗词学习系统
  • Sunshine游戏串流终极指南:如何在5分钟内搭建你的跨设备游戏王国
  • PubMed文献批量下载终极指南:3步实现科研效率提升90%
  • OpenClaw v0.3.0:本地可信AI中枢架构解析与部署实践
  • 2026年6月最新|自动化输送生产线厂家实测排名,权威榜单新鲜出炉 - 商业新知
  • 徽顺虹防水有限公司 张家口地区业务全景介绍 - 徽顺虹
  • 2026做商业综合体外立面,铝单板厂家选哪家更合适?——算清这笔账再决定 - 资讯报道
  • 2026兰美拉沉淀池选型攻略:从品牌筛选到企业考察,教你精准锁定优质合作方 - 品牌推荐大师
  • 2026 年 6 月欧米茄售后网点核验报告,多地维修新址开业 - 欧米茄中国服务中心
  • 嵌入式音频接口SAI:从I2S到TDM的配置与实战
  • 延迟标签场景下的概念漂移检测与AI治理:代理指标与SPRT实战
  • 2026护网蓝队威胁狩猎面试50道真题教程:SIEM规则编写+XDR告警研判+MITRE ATTCK映射
  • 终极免费Steam创意工坊下载器WorkshopDL:非Steam玩家的完美解决方案
  • 2026长沙黄金回收透明榜单,无套路诚信门店TOP6 - 奢侈品回收测评
  • MonkeyCode入门指南:为什么开源私有化AI编程助手是企业的最佳选择
  • 2026 成都闲置全套顶奢名表回收测评,12 家持证门店,避坑与估价干货 - 开心测评