[蓝桥杯]穿越雷区

题目描述

X 星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废。

某坦克需要从 A 区到 B 区去( A,B 区本身是安全区,没有正能量或负能量特征),怎样走才能路径最短?

已知的地图是一个方阵,上面用字母标出了 A,B 区,其它区都标了正号或负号分别表示正负能量辐射区。

例如:

A + - + -

- + - - +

- + + + -

+ - + - +

B + - + -

坦克车只能水平或垂直方向上移动到相邻的区。

输入描述

第一行是一个整数 nn,表示方阵的大小, 4≤n<1004≤n<100。

接下来是 nn 行,每行有 nn 个数据,可能是 A,B,+,- 中的某一个,中间用空格分开。A,B 都只出现一次。

输出描述

输出一个整数,表示坦克从 A 区到 B 区的最少移动步数。

如果没有方案,则输出 -1。

输入输出样例

示例

输入

5
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -

输出

10

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 512M

总通过次数: 4119  |  总提交次数: 4656  |  通过率: 88.5%

方法思路

  1. 问题分析:坦克从起点A到终点B,每一步必须交替经过正负能量辐射区(即从正到负或从负到正)。A和B是安全区,无正负属性。

  2. BFS应用:使用BFS按层搜索最短路径,每一步记录当前位置、上一步的符号状态(起始、正或负)和当前步数。

  3. 状态表示:使用三元组(x, y, sign)表示状态,其中sign=0表示起始状态(在A点),sign=1表示上一步经过正辐射区,sign=-1表示上一步经过负辐射区。

  4. 状态转移

    • 起始状态(A点)可移动到相邻的正或负辐射区。

    • 正辐射区下一步必须移动到负辐射区。

    • 负辐射区下一步必须移动到正辐射区。

  5. 终止条件:到达B点时返回当前步数(BFS首次到达即为最短路径)。

    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    // 定义四个移动方向:上、下、左、右
    const int dx[4] = {-1, 1, 0, 0};
    const int dy[4] = {0, 0, -1, 1};
    
    int main() {
        int n;
        cin >> n;
        vector> grid(n, vector(n));
        int start_x = -1, start_y = -1; // 起点A的坐标
        int end_x = -1, end_y = -1;     // 终点B的坐标
    
        // 读入网格数据,并记录起点和终点位置
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                cin >> grid[i][j];
                if (grid[i][j] == 'A') {
                    start_x = i;
                    start_y = j;
                } else if (grid[i][j] == 'B') {
                    end_x = i;
                    end_y = j;
                }
            }
        }
    
        // 初始化三维访问数组,记录每个位置在三种符号状态下的访问情况
        // 第三维:0->起始状态, 1->上一步为正, 2->上一步为负
        vector>> visited(n, vector>(n, vector(3, false)));
        queue> q; // 队列元素:(x, y, sign, step)
    
        // 起点入队,符号状态为0(起始),步数为0
        q.push(make_tuple(start_x, start_y, 0, 0));
        visited[start_x][start_y][0] = true;
    
        int ans = -1; // 初始化答案为-1(未找到路径)
    
        while (!q.empty()) {
            auto [x, y, sign, step] = q.front();
            q.pop();
    
            // 遍历四个移动方向
            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
    
                // 检查新位置是否越界
                if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
    
                // 到达终点B,记录答案并退出循环
                if (grid[nx][ny] == 'B') {
                    ans = step + 1;
                    break;
                }
    
                // 获取新位置的字符
                char c = grid[nx][ny];
                int new_sign = 0;
    
                if (c == '+') {
                    // 当前状态不能是正(即上一步不能是正)
                    if (sign == 1) continue;
                    new_sign = 1; // 新状态:下一步必须到负
                } else if (c == '-') {
                    // 当前状态不能是负(即上一步不能是负)
                    if (sign == -1) continue;
                    new_sign = -1; // 新状态:下一步必须到正
                } else {
                    // 遇到A或其他无效字符,跳过
                    continue;
                }
    
                // 计算新状态在visited中的索引(0->0, 1->1, -1->2)
                int sign_index = (new_sign == 0) ? 0 : (new_sign == 1 ? 1 : 2);
                // 如果新状态未访问过,则入队
                if (!visited[nx][ny][sign_index]) {
                    visited[nx][ny][sign_index] = true;
                    q.push(make_tuple(nx, ny, new_sign, step + 1));
                }
            }
            if (ans != -1) break; // 已找到路径,退出BFS
        }
    
        cout << ans << endl; // 输出答案(未找到时ans=-1)
        return 0;
    }

    代码解释

  6. 输入处理

    • 读取网格大小n和网格数据,记录起点A和终点B的坐标。

  7. BFS初始化

    • 使用三维数组visited记录每个位置在三种符号状态(起始、正、负)下的访问状态。

    • 起点A入队,符号状态为0(起始),步数为0。

  8. BFS搜索

    • 从队列取出当前状态(x, y, sign, step)

    • 向四个方向移动,计算新位置(nx, ny)

    • 若新位置是终点B,记录步数并退出。

    • 若新位置是正辐射区'+',检查上一步符号不能为正(确保交替),更新状态为1

    • 若新位置是负辐射区'-',检查上一步符号不能为负,更新状态为-1

    • 若新状态未访问过,则入队并标记。

  9. 结果输出

    • 若找到路径,输出最短步数;否则输出-1

你可能感兴趣的:(蓝桥杯,蓝桥杯,职场和发展,c++,算法,数据结构)