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

UVa 11724 Evaluate the Expression

题目描述

根据给定的BNF\texttt{BNF}BNF文法,一个数学表达式由变量(小写字母az)、运算符+*以及括号()组成,运算遵循常规的优先级规则:括号优先,乘法优先于加法。要求给每个变量赋一个正整数,使得在满足所有给定的不等式约束(例如a > b表示aaa必须严格大于bbb)的前提下,表达式的值最小。若不等式矛盾,输出-1

题目分析

本题包含三个主要难点:

  1. 表达式解析:需要按照优先级正确解析含有括号、加法和乘法的表达式,并能够替换变量值后求值。
  2. 变量约束建模:每个不等式x > y表示xxx的取值必须严格大于yyy的取值。由于所有变量都取正整数,这个关系可以转化为x≥y+1x \ge y + 1xy+1
  3. 最小化赋值:为了使表达式结果最小,应让每个变量的取值尽可能小,同时满足所有不等式。这等价于在有向图中求出每个节点的最小可能值

解题思路

1. 将不等式转化为有向图

考虑不等式x > y,因为变量都是正整数,所以等价于x≥y+1x \ge y + 1xy+1
我们可以建一个有向图,从yyyxxx连一条边,表示xxx的取值至少比yyy111

那么,每个变量的最小可能取值,就是图中从没有任何入边的节点(即没有“必须大于”其他变量的变量)出发,按照拓扑顺序递推得到的值:

  • 初始时,所有入度为000的节点赋值为111
  • 当处理节点uuu时,对其所有后继vvv,更新val[v]=max⁡(val[v],val[u]+1)val[v] = \max(val[v], val[u] + 1)val[v]=max(val[v],val[u]+1)
  • 这实际上是在DAG\texttt{DAG}DAG(有向无环图)上求最长路径,路径长度即为该节点的最小赋值。

2. 检测矛盾

如果图中存在环(例如a > b, b > c, c > a),则无法满足所有不等式,输出-1。环的检测可以通过拓扑排序实现:如果最终处理过的节点数少于图中总节点数,说明存在环。

3. 表达式解析与求值

我们可以使用递归下降解析,根据文法:

<expression> = <term> { '+' <term> } <term> = <factor> { '*' <factor> } <factor> = '(' <expression> ')' | <variable>

解析时构建一个语法树,每个节点可以是变量加法乘法。求值时,将变量节点替换为对应的数值,然后递归计算子树的值。

4. 整体流程

  1. 读入表达式,解析并构建语法树,同时收集所有出现的变量。
  2. 读入不等式,根据x > y建立有向边y→xy \to xyx,并统计入度。
  3. 对出现的变量进行拓扑排序,得到每个变量的最小赋值。若发现有环,输出-1
  4. 用得到的赋值对语法树求值,输出结果。

5. 复杂度分析

  • 表达式长度≤300\le 300300,递归解析复杂度为O(L)O(L)O(L)
  • 变量最多262626个,不等式最多400400400个,拓扑排序复杂度为O(V+E)O(V + E)O(V+E),完全可行。
  • 每个测试用例整体复杂度约为O(L+E)O(L + E)O(L+E)

代码实现

// Evaluate the Expression// UVa ID: 11724// Verdict: Accepted// Submission Date: 2026-06-03// UVa Run Time: 0.000s//// 版权所有(C)2026,邱秋。metaphysis # yeah dot net#include<bits/stdc++.h>usingnamespacestd;// 表达式节点类型enumNodeType{VAR,ADD,MUL};structExprNode{NodeType type;charvar;// 当 type == VAR 时有效ExprNode*left,*right;// 当 type == ADD 或 MUL 时有效ExprNode(charv):type(VAR),var(v),left(nullptr),right(nullptr){}ExprNode(NodeType t,ExprNode*l,ExprNode*r):type(t),left(l),right(r),var(0){}};// 解析表达式(递归下降)ExprNode*parseExpr(conststring&s,int&pos);ExprNode*parseTerm(conststring&s,int&pos);ExprNode*parseFactor(conststring&s,int&pos);ExprNode*parseExpr(conststring&s,int&pos){ExprNode*node=parseTerm(s,pos);while(pos<(int)s.size()&&s[pos]=='+'){pos++;// 跳过 '+'ExprNode*right=parseTerm(s,pos);node=newExprNode(ADD,node,right);}returnnode;}ExprNode*parseTerm(conststring&s,int&pos){ExprNode*node=parseFactor(s,pos);while(pos<(int)s.size()&&s[pos]=='*'){pos++;// 跳过 '*'ExprNode*right=parseFactor(s,pos);node=newExprNode(MUL,node,right);}returnnode;}ExprNode*parseFactor(conststring&s,int&pos){if(s[pos]=='('){pos++;// 跳过 '('ExprNode*node=parseExpr(s,pos);pos++;// 跳过 ')'returnnode;}else{// 变量returnnewExprNode(s[pos++]);}}// 收集表达式中的所有变量voidcollectVars(ExprNode*root,set<char>&vars){if(root->type==VAR){vars.insert(root->var);}else{collectVars(root->left,vars);collectVars(root->right,vars);}}// 计算表达式的值intevalExpr(ExprNode*root,map<char,int>&val){if(root->type==VAR)returnval[root->var];intleftVal=evalExpr(root->left,val);intrightVal=evalExpr(root->right,val);if(root->type==ADD)returnleftVal+rightVal;elsereturnleftVal*rightVal;}// 释放表达式树内存voidfreeExpr(ExprNode*root){if(root->type!=VAR){freeExpr(root->left);freeExpr(root->right);}deleteroot;}intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);intT;cin>>T;cin.ignore();// 忽略换行for(intcaseNum=1;caseNum<=T;++caseNum){string expr;getline(cin,expr);intI;cin>>I;cin.ignore();// 建图:graph[u] 表示 u 大于哪些节点vector<vector<char>>graph(26);vector<int>indeg(26,-1);// -1 表示该变量未出现set<char>varsSet;// 先收集表达式中的变量intpos=0;ExprNode*root=parseExpr(expr,pos);collectVars(root,varsSet);for(charv:varsSet)indeg[v-'a']=0;boolconsistent=true;for(inti=0;i<I;++i){string line;getline(cin,line);if(!consistent)continue;charx=line[0],y=line[2];// x > y => y -> x (x 至少是 y+1)// 但注意:x 和 y 必须出现在表达式中,题目保证如此if(indeg[x-'a']==-1||indeg[y-'a']==-1)continue;graph[y-'a'].push_back(x);indeg[x-'a']++;}// 拓扑排序求最小赋值queue<char>q;map<char,int>val;for(charv:varsSet){if(indeg[v-'a']==0){q.push(v);val[v]=1;}}intprocessed=0;while(!q.empty()){charu=q.front();q.pop();processed++;for(charv:graph[u-'a']){// v 至少比 u 大 1val[v]=max(val[v],val[u]+1);indeg[v-'a']--;if(indeg[v-'a']==0)q.push(v);}}if(processed!=(int)varsSet.size()){consistent=false;}if(!consistent){cout<<"Case "<<caseNum<<": -1\n";}else{intresult=evalExpr(root,val);cout<<"Case "<<caseNum<<": "<<result<<"\n";}freeExpr(root);}return0;}
http://www.jsqmd.com/news/1195673/

相关文章:

  • 效率工具实战指南:从自动化到跨平台同步的核心应用
  • 每天认识一种投资品类:期货
  • C++17文件系统毫秒级目录扫描:4大优化策略与并发实战
  • 宝格丽闲置奢品安心变现指南,北京连锁实体一站式回收全解析 - 分享测评官
  • 2026天津迪奥二手流通市场深度测评:五大回收机构星级评级与避坑指南 - 二奢行情速报
  • 大连黄金回收选合扬,紧跟大盘报价,便捷服务更贴心 - 全国奢侈品回收
  • STM32 HAL库串口中断回调机制深度解析与实战应用
  • Cursor AI分页功能实战优化手册(企业级分页架构首次公开)
  • 郑州金水二手名表回收靠谱渠道,不套路不压价现场验货 - 全城热点
  • PilotGo-plugin-container与其他容器监控工具对比:为什么它更适合你?
  • GitLab CI/CD配置文件管理:从单一文件到集中化配置的进阶实践
  • GitHub Copilot 四大模型实战对比:Free/Pro/Business/Enterprise 如何选
  • N皇后遗传算法Python实战:编码设计、适应度函数与精英变异策略
  • 【P3128】树上路径点权加1|倍增LCA + 树上差分
  • Excel公式不刷新、表格乱码、中文断行——Kimi阅读异常全诊断手册,含5类高频报错代码对照表
  • CCPS监控与告警系统:Prometheus、Grafana与自定义指标的实战配置
  • 福州名表全套溢价被吞?认准靠谱手表回收店铺,附件加价明细全部公开 - 每日生活报
  • 为什么说大模型的推理,其实是“两份工作”?
  • 成都市金牛区轮胎更换靠谱的 - 资讯纵览
  • 亲身到店探访长沙劳力士官方售后服务中心|官方地址及24小时售后电话(2026年7月最新) - 劳力士官方服务中心
  • 51单片机(三)独立按键消抖与状态机实战
  • TK1终端优化五步法:从卡顿到秒响应的实操指南
  • 金水花园路名表回收,线上免费估价,30 分钟上门 - 全城热点
  • 科研信息过滤系统:90分钟精读4篇论文的方法论
  • 宁波蒂芙尼六爪钻戒回收,微笑项链钥匙吊坠,发图即估价 - 大牌深度测评
  • 长沙岳麓区保洁收纳|维小达|日常保洁、深度保洁、开荒保洁、窗户保洁、收纳整理、暖气清洗、家电清洗全屋家政一站式清洁收纳养护服务 - 一点传媒
  • 前端三基石:从后端视角理解 HTML、CSS 与 JavaScript
  • 每天认识一种投资品类:股票
  • kucx实战指南:5个步骤集成不同通信库的完整方案
  • 姑苏区2026闲置包包回收防骗宝典|深度揭秘套路+完整维权流程+合规正规门店合集 - 生活时报