1 条题解

  • 0
    @ 2025-11-25 23:18:17

    Karel 机器人解释器题解

    题目分析

    这道题要求实现一个简化版 Karel 机器人的解释器。Karel 处在一个网格世界中,可以执行移动、转向、条件判断、循环和子程序调用等操作。我们需要正确解释执行给定的程序,并输出机器人的最终状态或判断程序是否无限循环。

    关键思路

    1. 网格表示:使用二维数组表示网格,'.'表示可通行,'#'表示障碍物
    2. 机器人状态:记录位置(x,y)和朝向(n/s/e/w)
    3. 子程序处理:使用映射存储子程序定义
    4. 程序解释:递归下降解释器,处理基本命令和控制结构
    5. 无限循环检测:通过步数限制来检测可能无限循环的程序

    算法步骤

    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

    算法特点

    1. 递归解释:使用递归方式处理程序执行,自然处理嵌套结构
    2. 步数限制:通过限制总步数来检测无限循环
    3. 括号匹配:正确解析嵌套的控制结构
    4. 状态维护:实时更新机器人位置和朝向

    复杂度分析

    • 时间复杂度:O(总步数),受MAX_STEPS限制
    • 空间复杂度:O(r×c + 程序总长度),用于存储网格和程序

    这个解决方案能够正确处理各种Karel程序,包括基本移动、转向、条件判断、循环和子程序调用,并能检测无限循环的情况。

    • 1

    信息

    ID
    5589
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者