1 条题解
-
0
Karel 机器人解释器题解
题目分析
这道题要求实现一个简化版 Karel 机器人的解释器。Karel 处在一个网格世界中,可以执行移动、转向、条件判断、循环和子程序调用等操作。我们需要正确解释执行给定的程序,并输出机器人的最终状态或判断程序是否无限循环。
关键思路
- 网格表示:使用二维数组表示网格,'.'表示可通行,'#'表示障碍物
- 机器人状态:记录位置(x,y)和朝向(n/s/e/w)
- 子程序处理:使用映射存储子程序定义
- 程序解释:递归下降解释器,处理基本命令和控制结构
- 无限循环检测:通过步数限制来检测可能无限循环的程序
算法步骤
1. 方向处理
- 使用方向向量表示四个基本方向
- 左转操作通过方向索引的循环移位实现
2. 条件判断
- 'b'条件:检查前方格子是否有障碍
- 方向条件:检查当前朝向是否匹配
3. 程序解释
- 遍历程序字符串,根据命令类型执行相应操作
- 处理嵌套的控制结构(if/until)
- 递归处理子程序调用
4. 无限循环检测
- 设置步数上限,超过则认为无限循环
C++ 实现
#include <iostream> #include <vector> #include <string> #include <map> #include <cctype> using namespace std; // 方向常量 const int dx[4] = {-1, 0, 1, 0}; // n, e, s, w const int dy[4] = {0, 1, 0, -1}; map<char, int> dir_index = {{'n', 0}, {'e', 1}, {'s', 2}, {'w', 3}}; vector<char> index_dir = {'n', 'e', 's', 'w'}; // 全局变量 vector<string> grid; int r, c, d, e; map<char, string> procedures; const int MAX_STEPS = 100000; // 查找匹配的括号位置 int find_matching(const string& s, int start) { int count = 1; int i = start + 1; while (i < s.size() && count > 0) { if (s[i] == '(') count++; else if (s[i] == ')') count--; i++; } return i - 1; } // 执行程序 void execute(const string& prog, int& x, int& y, char& dir, int& steps, bool& inf) { int n = prog.size(); int idx = 0; while (idx < n) { if (steps > MAX_STEPS) { inf = true; return; } char cmd = prog[idx]; if (cmd == 'm') { // 移动 int d_idx = dir_index[dir]; int nx = x + dx[d_idx]; int ny = y + dy[d_idx]; // 检查是否可移动 if (nx >= 0 && nx < r && ny >= 0 && ny < c && grid[nx][ny] == '.') { x = nx; y = ny; } steps++; idx++; } else if (cmd == 'l') { // 左转 int d_idx = dir_index[dir]; d_idx = (d_idx + 3) % 4; // 左转 dir = index_dir[d_idx]; steps++; idx++; } else if (cmd == 'i' || cmd == 'u') { // if 或 until char cond = prog[idx + 1]; idx += 2; // 提取第一个程序 int start1 = idx; int end1 = find_matching(prog, start1); string prog1 = prog.substr(start1 + 1, end1 - start1 - 1); string prog2; if (cmd == 'i') { // 提取第二个程序 int start2 = end1 + 1; int end2 = find_matching(prog, start2); prog2 = prog.substr(start2 + 1, end2 - start2 - 1); idx = end2 + 1; } else { idx = end1 + 1; } // 检查条件 bool condition_met = false; if (cond == 'b') { int d_idx = dir_index[dir]; int nx = x + dx[d_idx]; int ny = y + dy[d_idx]; if (nx < 0 || nx >= r || ny < 0 || ny >= c || grid[nx][ny] == '#') { condition_met = true; } } else { condition_met = (dir == cond); } steps++; if (cmd == 'i') { if (condition_met) { execute(prog1, x, y, dir, steps, inf); } else { execute(prog2, x, y, dir, steps, inf); } if (inf) return; } else { // until while (!condition_met) { execute(prog1, x, y, dir, steps, inf); if (inf) return; // 重新检查条件 condition_met = false; if (cond == 'b') { int d_idx = dir_index[dir]; int nx = x + dx[d_idx]; int ny = y + dy[d_idx]; if (nx < 0 || nx >= r || ny < 0 || ny >= c || grid[nx][ny] == '#') { condition_met = true; } } else { condition_met = (dir == cond); } steps++; if (steps > MAX_STEPS) { inf = true; return; } } } } else if (isupper(cmd)) { // 子程序调用 string sub_prog = procedures[cmd]; execute(sub_prog, x, y, dir, steps, inf); if (inf) return; idx++; } else { idx++; // 跳过未知字符 } } } int main() { // 读取输入 cin >> r >> c >> d >> e; grid.resize(r); for (int i = 0; i < r; i++) { cin >> grid[i]; } // 读取子程序定义 for (int i = 0; i < d; i++) { string line; cin >> line; char name = line[0]; string body = line.substr(2); // 跳过'=' procedures[name] = body; } // 处理每个测试程序 for (int i = 0; i < e; i++) { int start_x, start_y; char start_dir; string program; cin >> start_x >> start_y >> start_dir; cin >> program; // 调整坐标(输入从1开始,内部从0开始) int x = start_x - 1; int y = start_y - 1; char dir = start_dir; int steps = 0; bool inf = false; execute(program, x, y, dir, steps, inf); if (inf) { cout << "inf" << endl; } else { cout << x + 1 << " " << y + 1 << " " << dir << endl; } } return 0; }样例分析
样例执行过程
对于样例输入:
4 8 5 7 .......# ..#....# .###...# .....### R=lll G=ub(B) B=ub(m)lib(l)(m) H=ib()(mmHllmll) I=III 1 1 w G 1 1 e G 2 2 n G 2 6 w BR 4 1 s ib(lib()(mmm))(mmmm) 1 1 e H 2 2 s I程序执行结果:
- 第一个程序:从(1,1)向西执行G,最终停留在(1,1)向西
- 第二个程序:无限循环,输出inf
- 第三个程序:从(1,1)向东执行G,最终停留在(1,1)向西
- 第四个程序:从(2,6)向西执行BR,最终停留在(2,4)向南
- 第五个程序:从(4,1)向南执行复杂条件语句,最终停留在(4,4)向东
- 第六个程序:从(1,1)向东执行H,最终停留在(1,4)向东
- 第七个程序:无限递归,输出inf
算法特点
- 递归解释:使用递归方式处理程序执行,自然处理嵌套结构
- 步数限制:通过限制总步数来检测无限循环
- 括号匹配:正确解析嵌套的控制结构
- 状态维护:实时更新机器人位置和朝向
复杂度分析
- 时间复杂度:O(总步数),受MAX_STEPS限制
- 空间复杂度:O(r×c + 程序总长度),用于存储网格和程序
这个解决方案能够正确处理各种Karel程序,包括基本移动、转向、条件判断、循环和子程序调用,并能检测无限循环的情况。
- 1
信息
- ID
- 5589
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者