当前位置: 首页 > 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.gsyq.cn/news/1572730.html

相关文章:

  • Seedance 2.0:音视频节奏对齐的多模态生成技术栈
  • 爱回收报价透明吗?从一机一况定价到价保规则的完整拆解 - 资讯焦点
  • 速存!2026 年 6 月欧米茄官方维修门店最新地址全发布,全新全国统一售后热线同步上线 - 欧米茄中国服务中心
  • 如何快速免费解锁Wand专业版:终极游戏修改工具WandEnhancer完整指南
  • 集成电路展会哪家展会最具行业影响力?2026年集成电路展会推荐 - 品牌深度评测
  • DeepSeek V4 MoE大模型技术解析与昇腾910C本地部署指南
  • 2026年6月最新|自动化输送生产线厂家实测排名,权威榜单新鲜出炉 - 商业新知
  • 2026护网蓝队威胁狩猎面试50道真题教程:SIEM规则编写+XDR告警研判+MITRE ATTCK映射
  • MonkeyCode入门指南:为什么开源私有化AI编程助手是企业的最佳选择
  • 2026长沙黄金回收透明榜单,无套路诚信门店TOP6 - 奢侈品回收测评
  • 大同黄金贵金属回收推荐:六家靠谱店铺,覆盖全城安心变现 - 清奢黄金上门回收
  • 告别到手刀!南京名包回收门店资质核验全攻略 2026 实测 - 讯息早知道
  • LLM引导进化算法实现零样本时间序列数据插补
  • 大模型可靠性工程:从一致性到可审计的决策闭环
  • 通州区老房翻新品牌实测:金亿尚装饰工地体验全记录 - 起跑123
  • 2026年湖北中南技工学校最新招生简章 - 武汉中职最新信息发布
  • Control优先的AI辅助编程:程序员主权四层实践体系
  • Java面试中的陷阱与应对策略:避免常见错误
  • 2026 楼顶大字厂家哪家靠谱?5家稳品质品牌盘点! - 资讯焦点
  • 采购一体化预制泵站,报价单上看不见的成本在哪里 - 资讯报道
  • π0.7可操控大模型:从指令约束到物理级可控的AI新范式
  • 企业管理咨询公司哪家好?聚焦三大核心能力,避开选型常见误区 - 资讯焦点
  • 2026聚氨酯轮推荐靠谱的品牌选购指南 - 热点速览
  • 2026油皮瑕疵皮测评:ZIJ粉底液vs美宝莲巨持妆,遮瑕力比拼 - 热点速览
  • Gemini 3.1 Flash Lite深度解析:轻量原生架构与多模态流式工程实践
  • 安阳市黄金回收实体店怎么选?这份清单帮你货比三家 - 奢金阁
  • 基于MC56F8006 DSC的分布式RGB LED网络驱动方案设计与实现
  • Maya1 TTS实战:从零构建可控、可调、可部署的语音生成系统
  • 如何快速掌握开源硬件控制:5个终极技巧解锁OMEN游戏本性能
  • 2026年6月昆明靠谱公司注册代办机构权威推荐 本土企业实测甄选 - 品牌智鉴榜