top1编程
← 返回题目
题解

最小体力值

1 条题解

  • 0
    @ 2026-8-5 0:56:09

    解题思路

    小童走路不会拐弯,只能朝“上、下、左、右”其中一个方向直走,直到走出方阵。所以要离开方阵,一共只有 4 种走法:

    • 一直往上走,经过上方一串格子;
    • 一直往下走,经过下方一串格子;
    • 一直往左走,经过左边一串格子;
    • 一直往右走,经过右边一串格子。

    每种走法里,经过的每一个 '*' 都要消耗 1 个体力。我们只要把 4 种走法的体力值都算出来,取最小的那个,就是答案。

    怎么“一步一步走”呢?我们借助方向数组:

    • 上:行号 -1(dx=-1),列号不变(dy=0);
    • 下:行号 +1;
    • 左:列号 -1;
    • 右:列号 +1。

    用 while 循环模拟:从起点出发,每走一步先移动一下位置,然后检查——

    1. 如果走出边界(行号 <1 或 >m,列号 <1 或 >n),就停下来,这条路线走完了;
    2. 如果没出界,再看当前位置是不是 '*',是的话体力值 +1。

    小童自己站的位置是 '.',并且他走第一步就离开了原地,所以自己的格子不会计入体力值。

    参考代码

    // P4453 最小体力值:从起点沿上下左右四个方向直走,分别数经过的*的个数,取最小值
    #include <iostream>
    using namespace std;
    
    char a[20][20]; // 字符方阵
    int dx[4] = {-1, 1, 0, 0}; // 上下左右的行变化
    int dy[4] = {0, 0, -1, 1}; // 上下左右的列变化
    
    int main() {
        int m, n, x, y;
        cin >> m >> n;
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++)
                cin >> a[i][j]; // 字符之间有空格,直接逐个读
        cin >> x >> y;          // 小童当前所在的行和列
        int ans = 1000000;      // 最小体力值,先设一个大数
        for (int d = 0; d < 4; d++) { // 枚举四个方向
            int cnt = 0;         // 本方向经过的*的个数
            int i = x, j = y;
            while (true) {
                i += dx[d];
                j += dy[d];
                if (i < 1 || i > m || j < 1 || j > n) break; // 走出方阵,结束
                if (a[i][j] == '*') cnt++;                   // 路过雷点消耗1体力
            }
            if (cnt < ans) ans = cnt; // 更新最小体力值
        }
        cout << ans << endl;
        return 0;
    }
    

    复杂度分析

    • 每个方向最多走 m 或 n 步,一共 4 个方向,时间复杂度是 O(m + n)。
    • 需要把整个方阵存下来,空间复杂度是 O(m × n)。
    • 1