题解:洛谷 P7995 Walking Home

【题目来源】

洛谷:P7995 [USACO21DEC] Walking Home B - 洛谷

【题目描述】

奶牛 Bessie 正准备从她最喜爱的草地回到她的牛棚。

农场位于一个 \(N\times N\) 的方阵上\((2\le N\le 50)\),其中她的草地在左上角,牛棚在右下角。Bessie 想要尽快回家,所以她只会向下或向右走。有些地方有草堆(haybale),Bessie 无法穿过;她必须绕过它们。

Bessie 今天感到有些疲倦,所以她希望改变她的行走方向至多 \(K\)\((1\le K\le 3)\)

Bessie 有多少条不同的从她最爱的草地回到牛棚的路线?如果一条路线中 Bessie 经过了某个方格而另一条路线中没有,则认为这两条路线不同。

【输入】

每个测试用例的输入包含 \(T\) 个子测试用例,每个子测试用例描述了一个不同的农场,并且必须全部回答正确才能通过整个测试用例。输入的第一行包含 \(T(1\le T\le 50)\)。每一个子测试用例如下。

每个子测试用例的第一行包含 \(N\)\(K\)

以下 \(N\) 行每行包含一个长为 \(N\) 的字符串。每个字符为 .,如果这一格是空的,或 \(H\),如果这一格中有草堆。输入保证农场的左上角和右下角没有草堆。

【输出】

输出 \(T\) 行,第 \(i\) 行包含在第 \(i\) 个子测试用例中 Bessie 可以选择的不同的路线数量。

【输入样例】

7
3 1
...
...
...
3 2
...
...
...
3 3
...
...
...
3 3
...
.H.
...
3 2
.HH
HHH
HH.
3 3
.H.
H..
...
4 3
...H
.H..
....
H...

【输出样例】

2
4
6
2
0
0
6

【核心思想】

  1. 问题分析:给定 \(N \times N\) 网格,从左上角 \((1,1)\) 到右下角 \((N,N)\),只能向下或向右走,避开草堆 H。要求改变方向至多 \(K\)\(1 \leq K \leq 3\))的不同路径数。本质是一个带方向变化约束的网格路径计数问题。

  2. 算法选择

    • BFS状态扩展:每个状态包含位置 \((x, y)\)、上一步方向 \(d\)\(0\) 为右,\(1\) 为下)、已转弯次数 \(\text{step}\)。用队列进行状态扩展,统计到达终点的合法状态数。
  3. 关键步骤

    • 初始化:将起点 \((1, 1)\) 以方向 \(-1\)(无方向)、转弯次数 \(0\) 入队
    • BFS循环
      • 出队状态 \(\text{tp}\),若 \(\text{tp}.\text{step} > K\) 则剪枝跳过
      • 若到达 \((N, N)\)\(\text{step} \leq K\)\(\text{ans}++\)
      • 方向扩展:枚举两个方向 \(i \in \{0, 1\}\)(右、下):
        • 计算新坐标 \((\text{xx}, \text{yy}) = (\text{tp}.x + \text{dx}[i], \text{tp}.y + \text{dy}[i])\)
        • 边界与障碍判定:越界或遇到 H 则跳过
        • 转弯次数更新
          • \(\text{tp}.d = -1\)(起点):新状态转弯次数为 \(0\)
          • \(\text{tp}.d \neq i\)(方向改变):\(\text{step} + 1\)
          • \(\text{tp}.d = i\)(方向不变):\(\text{step}\) 不变
        • 若新状态转弯次数 \(> K\) 则剪枝,否则入队
    • 输出答案:每个测试用例输出 \(\text{ans}\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(T \cdot N^2 \cdot K)\),每个状态最多被访问 \(O(K)\) 次(不同转弯次数)
    • 空间复杂度:\(O(N^2 \cdot K)\),队列存储状态
  5. 状态BFS带约束路径计数的核心思想

    • 状态维度设计:将"转弯次数"纳入状态,避免简单DP无法记录方向历史的问题
    • 方向连续性利用:同方向移动不增加转弯次数,只有方向切换时才计数,保证状态转移正确性
    • 早期剪枝:一旦转弯次数超过 \(K\) 立即停止扩展,减少无效状态
    • BFS与DFS的选择:由于只需要计数而非求最短路径,BFS和DFS均可,但BFS按层扩展更符合"路径探索"直觉
    • 适用于带约束网格路径、方向限制、状态空间搜索类问题

【解题思路】

【算法标签】

普及 #BFS-二维

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int t, n, k;
int path[2500];
char a[55][55];
int dx[2]={0,1}, dy[2]={1,0};  // 定义向右和向下的偏离坐标
struct node {  // 定义结构体,包含x、y坐标,上一次的方向,以及调整次数step
    int x, y, d, step;
};
int main()
{
    cin >> t;  // 输入t
    while (t--) {  // 遍历t次询问
        cin >> n >> k;  // 输入n和k
        for (int i=1; i<=n; i++) {  // 记录n*n矩阵
            for (int j=1; j<=n; j++) {
                cin >> a[i][j];
            }
        }
        queue<node> q;  // 定义队列
        node tp = {1, 1, -1, 0};  // 定义队头
        q.push(tp);  // 压入队列中
        int ans=0;  // 每轮询问初始化路线数量为0
        while (!q.empty()) {  // 当队列不为空
            tp = q.front();  // 取出队头
            q.pop();
            if (tp.step>k) {  // 剪枝:如果队头的调整次数大于k了,则继续下次循环
                continue;
            }
            if (tp.x==n && tp.y==n) {  // 如果队头坐标已经到达[n,n]
                if (tp.step<=k) {  // 如果次数调整次数小于等于k(肯定满足,因为上面特判了不满足)
                    ans++;  // 路线数量加1
                }
                continue;  // 继续下次循环
            }
            for (int i=0; i<2; i++) {  // 分别计算向右和向下的路线
                int xx=tp.x+dx[i], yy=tp.y+dy[i];  // 定义偏移后的坐标
                if (xx<1 || xx>n || yy<1 || yy>n || a[xx][yy]=='H') continue;  // 如果坐标越界或者遇到'H',则继续下次循环
                node t;  // 定义即将压入队列的t
                if (tp.d == -1) {  // 如果是队头坐标[1,1]
                    t = {xx, yy, i, 0};  // 则调整次数为0
                } else if (tp.d != i) {  // 否则,只要即将要调整的方向与上一次过来的方向不一致
                    t = {xx, yy, i, tp.step+1};  // 调整次数加1
                } else {  // 调整方向与上次过来的方向一致
                    t = {xx, yy, i, tp.step};  // 调整次数还是上次的调整次数
                }
                if (t.step>k) break;  // 剪枝:如果此时t的调整次数大于k,就不用再继续了
                q.push(t);  // 将t压入队列中
            }
        }
        cout << ans << endl;  // 打印路线总数
    }

    return 0;
}

【运行结果】

7
3 1
...
...
...
2
3 2
...
...
...
4
3 3
...
...
...
6
3 3
...
.H.
...
2
3 2
.HH
HHH
HH.
0
3 3
.H.
H..
...
0
4 3
...H
.H..
....
H...
6
posted @ 2026-08-29 09:39  团爸讲算法  阅读(9)  评论(0)    收藏  举报