25. 进圈

目录

题目

思路

注意事项

C++完整代码(含详细注释)


题目

Description
龙龙最近迷上了一款名叫 PUBG(PLAYERUNKNOWN’S BATTLEGROUNDS)的手游,那是一款关乎生存挑战的 RPG 逃亡游戏。
考虑到游戏的环节过于复杂,龙龙决定简化一下场景:整个地图可以看做一个长为 ​ 宽为 ​ 的二维格点平面。龙龙需要从  逃亡到  以逃离毒圈,但有些格点上存在障碍#不能行走,有些格点是沙地.。龙龙只能移动在允许行走的沙地上,同时每一时刻,龙龙只能朝着当前位置周围的上、下、左、右四个方向移动。同时因为龙龙使用了能量饮料,每分钟最多可以朝着一个方向行走  步。
毒圈快要来啦,请你帮龙龙尽快安排一下可行的路线,使得它能够以最短的时间顺利进圈。
Input
第一行输入三个正整数  和  表示地图的大小还有龙龙每分钟最多可以移动的步数;
接下来  行,每行包含  个字符,其中第  行第  个字符表示坐标  的路况,它可能是#,这表示这个格点是障碍区,不能行走,也可能是.表示沙地;
最后一行输入四个正整数  由空格间隔开,表示龙龙的初始位置和目标位置。
Output
请输出一个正整数 ,表示龙龙从  到  进圈最少需要的时间(分钟),如果龙龙最终不能进圈,则请输出-1。
Hint
对于样例,龙龙第一分钟走  步,从  到 ,第二分钟从  到 ,第三分钟从  走到  顺利进圈。


思路

首先,程序读取输入的地图大小n和m,以及龙龙每分钟最多可以移动的步数k。然后,程序读取地图的每一行,并将其存储在map数组中。

int n, m, k; // 地图大小n和m,每分钟最多移动步数k
    int x1, y1, x2, y2; // 初始位置和目标位置的坐标
    scanf("%d%d%d", &n, &m, &k); // 读取输入
 
    for (int i = 0; i < n; ++i) {
        scanf("%s", &map[i]); // 读取地图的每一行
    }

接下来,程序读取龙龙的初始位置和目标位置。将初始位置加入到队列que中,并初始化ans为-1(表示无法进圈)。

scanf("%d%d%d%d", &x1, &y1, &x2, &y2); // 读取初始位置和目标位置
 
    que.push(node(x1 - 1, y1 - 1, 0)); // 将初始位置加入队列
    int ans = -1; // 初始化答案为-1,表示无法进圈
 

然后,程序开始进行BFS搜索。每次从队列中取出一个节点tmp,然后根据龙龙可以移动的步数k,尝试向上、下、左、右四个方向移动。如果移动后的位置越界或是障碍物(#),则停止继续移动。如果移动到了目标位置,则更新ans为当前步数加1,并输出ans,然后程序结束。否则,将新的位置加入队列que中,并将visited数组中对应的位置标记为已访问。

 que.push(node(x1 - 1, y1 - 1, 0)); // 将初始位置加入队列
    int ans = -1; // 初始化答案为-1,表示无法进圈
 
    while (!que.empty()) {
        node tmp = que.front(); // 取出队列中的第一个节点
        que.pop(); // 弹出队列中的第一个节点
 
        for (int i = 0; i < 4; ++i) { // 尝试四个方向移动
            for (int j = 1; j < k + 1; j++) { // 尝试每个方向移动k步
                int x = tmp.x + dir_x[i] * j; // 计算新的x坐标
                int y = tmp.y + dir_y[i] * j; // 计算新的y坐标
 
                // 如果移动后的位置越界或是障碍物,则停止继续移动
                if (x < 0 || x >= n || y < 0 || y >= m || map[x][y] == '#') {
                    break;
                }
 
                // 如果位置已被访问过,则继续尝试下一个位置
                if (visited[x][y] == 1) {
                    continue;
                }
 
                // 如果移动到了目标位置,则更新答案为当前步数加1,并输出答案,然后程序结束
                if (x == x2 - 1 && y == y2 - 1) {
                    ans = tmp.step + 1;
                    printf("%d\n", ans);
                    return 0;
                }
 
                // 将新的位置加入队列,并将visited数组中对应的位置标记为已访问
                que.push(node(x, y, tmp.step + 1));
                visited[x][y] = 1;
            }
        }
    }

最后,如果队列为空,表示无法找到到达目标位置的路径,输出ans(初始值为-1)。

这段代码的时间复杂度为O(nmk),其中n和m分别是地图的行数和列数,k是龙龙每分钟最多可以移动的步数。空间复杂度为O(n*m),用于存储地图和visited数组。


注意事项

  1. 输入时需要将坐标减1,因为数组索引是从0开始的,而地图坐标是从1开始的。
  2. 在判断位置是否越界时,需要考虑边界条件,即x >= 0 && x < n && y >= 0 && y < m。
  3. 在判断位置是否为障碍物时,需要判断map[x][y]是否等于'#'。
  4. 在判断位置是否已被访问过时,需要判断visited[x][y]是否等于1。
  5. 在将新的位置加入队列时,需要将新的位置的坐标和步数更新为tmp.x + dir_x[i] * j, tmp.y + dir_y[i] * j, tmp.step + 1。
  6. 在将新的位置加入队列之前,需要将visited数组中对应的位置标记为已访问,即visited[x][y] = 1。
  7. 在找到目标位置之后,需要及时输出答案并结束程序,即在ans被更新后,使用return 0退出循环。
  8. 输出答案时,需要考虑无法进圈的情况,即ans为-1的情况。
  9. 代码中的地图大小n和m的范围需要根据实际情况进行调整,保证不超过数组的最大长度。
  10. 代码中的每分钟最多移动步数k需要根据实际情况进行调整,保证不超过地图的大小。

C++完整代码(含详细注释)

有查重,改改再提交乐学!!!

#include <queue>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
 
const int dir_x[4] = { 0, 0, 1, -1 }; // 四个方向的x坐标变化
const int dir_y[4] = { 1, -1, 0, 0 }; // 四个方向的y坐标变化
 
struct node {
    int x, y; // 当前节点的坐标
    int step; // 到达当前节点的步数
    node(int _x, int _y, int _step) : x(_x), y(_y), step(_step) {} // 构造函数
};
 
queue<node> que; // 定义一个队列用于BFS搜索
int visited[1000][1000]; // 记录节点是否被访问过的数组
char map[1000][1000]; // 存储地图的数组
 
int main() {
    int n, m, k; // 地图大小n和m,每分钟最多移动步数k
    int x1, y1, x2, y2; // 初始位置和目标位置的坐标
    scanf("%d%d%d", &n, &m, &k); // 读取输入
 
    for (int i = 0; i < n; ++i) {
        scanf("%s", &map[i]); // 读取地图的每一行
    }

    scanf("%d%d%d%d", &x1, &y1, &x2, &y2); // 读取初始位置和目标位置
 
    que.push(node(x1 - 1, y1 - 1, 0)); // 将初始位置加入队列
    int ans = -1; // 初始化答案为-1,表示无法进圈
 
    while (!que.empty()) {
        node tmp = que.front(); // 取出队列中的第一个节点
        que.pop(); // 弹出队列中的第一个节点
 
        for (int i = 0; i < 4; ++i) { // 尝试四个方向移动
            for (int j = 1; j < k + 1; j++) { // 尝试每个方向移动k步
                int x = tmp.x + dir_x[i] * j; // 计算新的x坐标
                int y = tmp.y + dir_y[i] * j; // 计算新的y坐标
 
                // 如果移动后的位置越界或是障碍物,则停止继续移动
                if (x < 0 || x >= n || y < 0 || y >= m || map[x][y] == '#') {
                    break;
                }
 
                // 如果位置已被访问过,则继续尝试下一个位置
                if (visited[x][y] == 1) {
                    continue;
                }
 
                // 如果移动到了目标位置,则更新答案为当前步数加1,并输出答案,然后程序结束
                if (x == x2 - 1 && y == y2 - 1) {
                    ans = tmp.step + 1;
                    printf("%d\n", ans);
                    return 0;
                }
 
                // 将新的位置加入队列,并将visited数组中对应的位置标记为已访问
                que.push(node(x, y, tmp.step + 1));
                visited[x][y] = 1;
            }
        }
    }
 
    printf("%d\n", ans); // 输出答案
 
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

榆榆欸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值