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

UVa 1596 Bug Hunt

题目分析

本题要求我们在一个简化的编程语言中检测两种类型的错误:

  1. 数组索引越界:访问数组时索引不在 [0,n−1][0, n-1][0,n1] 范围内
  2. 使用未赋值的元素:在表达式中引用了尚未被赋值的数组元素

输入格式

  • 多组测试数据,每组以 . 结束
  • 整个输入以单独的 . 结束
  • 每行不超过 808080 个字符(不包括换行符)
  • 程序不超过 100010001000

输出要求

对于每个程序,输出第一个出现错误的赋值语句的行号(从 111 开始计数),如果没有错误则输出 000

解题思路

关键观察

  1. 语法保证正确:题目保证输入程序语法正确,数组在使用前都已声明
  2. 执行顺序:程序按行顺序执行,声明语句不会触发错误
  3. 大小写敏感:数组名区分大小写
  4. 大数组处理:数组长度可能达到 231−12^{31}-12311,不能预先初始化所有元素

算法设计

我们采用以下数据结构:

  • arraySize:记录每个数组的大小
  • assigned:记录数组元素是否被赋值过
  • arrayValues:存储数组元素的实际值

核心算法步骤:

  1. 读取程序:将每个数据集读入字符串数组
  2. 处理声明语句:记录数组大小,但不预先初始化元素(避免大数组问题)
  3. 处理赋值语句
    • 解析左值数组和索引表达式
    • 计算右值表达式
    • 在计算过程中检查索引越界和未赋值错误
  4. 惰性检查:只有在访问元素时才检查其状态

表达式求值

表达式可能是:

  • 数字:直接转换为整数
  • 数组访问:递归计算索引,然后检查边界和赋值状态

代码实现

// Bug Hunt
// UVa ID: 1596
// Verdict: Accepted
// Submission Date: 2025-10-24
// UVa Run Time: 0.000s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net#include <bits/stdc++.h>using namespace std;// 存储数组名到大小的映射
map<string, int> arraySize;
// 存储数组元素的实际值
map<pair<string, int>, int> arrayValues;
// 记录数组元素是否被赋值过
map<pair<string, int>, bool> assigned;// 表达式求值函数
// 参数:expr - 表达式字符串,currentLine - 当前行号,bugLine - 引用参数,用于记录错误行号
// 返回值:表达式的值,如果出错返回 -1
int evaluateExpression(const string& expr, int currentLine, int& bugLine) {// 如果是数字,直接转换为整数if (isdigit(expr[0])) {return stoi(expr);}// 数组访问表达式:name[inner_expr]size_t bracketPos = expr.find('[');string arrayName = expr.substr(0, bracketPos);string innerExpr = expr.substr(bracketPos + 1, expr.size() - bracketPos - 2);// 递归计算内部表达式(索引)int index = evaluateExpression(innerExpr, currentLine, bugLine);if (bugLine != 0) return -1; // 如果内部表达式已出错,直接返回// 检查索引是否越界if (index < 0 || index >= arraySize[arrayName]) {bugLine = currentLine;return -1;}// 检查该元素是否被赋值过(惰性检查)if (assigned.find({arrayName, index}) == assigned.end() || !assigned[{arrayName, index}]) {bugLine = currentLine;return -1;}// 返回数组元素的实际值return arrayValues[{arrayName, index}];
}int main() {string line;// 读取多组测试数据,直到遇到单独的 "." while (getline(cin, line) && line != ".") {vector<string> programLines;programLines.push_back(line);// 读取一个完整程序,直到遇到 "."while (getline(cin, line) && line != ".") {programLines.push_back(line);}// 清空数据结构,为新程序做准备arraySize.clear();arrayValues.clear();assigned.clear();int bugLine = 0; // 记录第一个错误的行号// 逐行处理程序for (int lineNum = 0; lineNum < programLines.size(); lineNum++) {const string& statement = programLines[lineNum];size_t equalPos = statement.find('=');if (equalPos == string::npos) {// 声明语句:array_name[size]size_t bracketPos = statement.find('[');string arrayName = statement.substr(0, bracketPos);string sizeStr = statement.substr(bracketPos + 1, statement.size() - bracketPos - 2);int size = stoi(sizeStr);arraySize[arrayName] = size;// 注意:不预先初始化元素,避免大数组问题} else {// 赋值语句:left = rightstring leftPart = statement.substr(0, equalPos);string rightPart = statement.substr(equalPos + 1);// 解析左值:array_name[index_expr]size_t bracketPos = leftPart.find('[');string leftArrayName = leftPart.substr(0, bracketPos);string leftIndexExpr = leftPart.substr(bracketPos + 1, leftPart.size() - bracketPos - 2);// 计算左值索引int leftIndex = evaluateExpression(leftIndexExpr, lineNum + 1, bugLine);if (bugLine != 0) break; // 如果计算过程出错,终止处理// 检查左值索引是否越界if (leftIndex < 0 || leftIndex >= arraySize[leftArrayName]) {bugLine = lineNum + 1;break;}// 计算右值表达式int rightValue = evaluateExpression(rightPart, lineNum + 1, bugLine);if (bugLine != 0) break; // 如果计算过程出错,终止处理// 执行赋值:标记元素已赋值并存储值assigned[{leftArrayName, leftIndex}] = true;arrayValues[{leftArrayName, leftIndex}] = rightValue;}// 如果已发现错误,提前终止if (bugLine != 0) break;}// 输出结果cout << bugLine << endl;}return 0;
}

算法复杂度分析

  • 时间复杂度O(L×E)O(L \times E)O(L×E),其中 LLL 是程序行数,EEE 是表达式深度
  • 空间复杂度O(N+M)O(N + M)O(N+M),其中 NNN 是数组数量,MMM 是被赋值的元素数量

总结

本题的关键在于正确处理表达式求值过程中的错误检测,特别是对于大数组的惰性处理。通过递归求值和惰性检查,我们能够高效地检测出数组访问中的各种错误情况。

http://www.dtcms.com/a/524163.html

相关文章:

  • 企业数据仓库
  • 如何用 HTML 生成 PC 端软件
  • Apache Spark算法开发指导-特征转换Normalizer
  • 泗洪网站建设变化型网页网站有哪些
  • 渭南哪家公司可以做网站小程序开发制作价格
  • 广州城市建设规划局网站我想给网站网站做代理
  • 蓝蜂 MQTT 网关打通 120 台设备数据,助汽车零部件厂降本 40%​
  • C++异常详细介绍
  • AKKO 3180键盘插到联想笔记本无法使用问题
  • 打造高清3D虚拟世界|零基础学习Unity HDRP高清渲染管线(第六天)
  • 从项目中学习CAN和CANFD报文结构(新手入门)
  • SpreadJS 赋能在线 Excel:协同编辑与精细化权限管控的技术实现
  • RabbitMQ 持久性详解
  • cms网站栏目介绍html免费模板下载
  • 太原网站建设培训班wordpress购买按钮插件
  • 北斗导航 | 接收机自主完好性监测(RAIM)在列车中的应用:原理、现状、挑战与案例
  • 前端Sass完全指南:从入门到精通
  • 网站建设地域名高校网站建设 网站群
  • 破局制造业数据孤岛,大腾智能PDM实现产研协同
  • 小程序文件在线显示(支持word,图片,视频等)
  • 记录自己写项目的第三天,springbot+redis+rabbitma高并发项目
  • Linux下查看系统启动时间、运行时间
  • Linux中子系统注册subsystem_register等函数的实现
  • MFC应用程序,工作线程学习记录
  • 在什么网站做公司人员增减wordpress主题标签
  • 广州新塘网站制作推广网站服务器检测
  • 金仓多模数据库:电子证照系统国产化替代MongoDB的优选方案
  • SQL之键与约束——数据库设计的基石与数据完整性的守护者
  • 百度网站收录查询地址保定网站推广多少钱
  • 移动端网站如何开发一呼百应网