USACO历年青铜组真题解析 | 2021年12月Walking Home

欢迎大家订阅我的专栏:算法题解:C++与Python实现
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!

专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。

适合人群:

  • 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
  • 希望系统学习C++/Python编程的初学者
  • 想要提升算法与编程能力的编程爱好者

附上汇总贴:USACO历年青铜组真题解析 | 汇总-优快云博客


【题目描述】

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

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

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

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

【输入】

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

每个子测试用例的第一行包含 N 和 K

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

【输出】

输出 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

【代码详解】

#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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值