网易笔试题-地牢逃脱

地牢逃脱


题目

  • 给定一个 n 行 m 列的地牢,其中'.' 表示可以通行的位置,'X' 表示不可通行的障碍,牛牛从( x 0 , y 0 x_0,y_0 x0,y0 ) 位置出发,遍历这个地牢。
  • 和一般的游戏所不同的是,他每一步只能按照一些指定的方式遍历地牢,要求每一步都不可以超过地牢的边界,也不能到达障碍上。
  • 地牢的出口可能在任意某个可以通行的位置上。牛牛想知道出口在最坏情况下,他最少需要多少步才可以离开这个地牢。

输入描述:

  • 每个输入包含 1 个测试用例。每个测试用例的第一行包含两个整数 n , m n,m nm 1 ≤ n ≤ 50 ,      1 ≤ m ≤ 50 1 \leq n \leq 50,\;\;1 \leq m \leq 50 1n50,1m50),表示地牢的长和宽。
  • 接下来的 n 行,每行 m 个字符,描述地牢,地牢将至少包含两个'.'
  • 接下来的一行,包含两个整数$ x_0,y_0$,表示牛牛的出发位置( 0 ≤ x 0 &lt; n , &ThickSpace;&ThickSpace; 0 ≤ y 0 &lt; m 0 \leq x_0 &lt; n,\;\; 0 \leq y_0 &lt; m 0x0<n,0y0<m),左上角的坐标为 (0, 0),出发位置一定是 '.')。
  • 之后的一行包含一个整数 k( 0 &lt; k ≤ 50 0 &lt; k \leq 50 0<k50)表示牛牛合法的步长数,接下来的 k 行,每行两个整数 dx, dy 表示每次可选择移动的行和列步长( − 50 ≤ d x , d y ≤ 50 -50 \leq dx, dy \leq 50 50dx,dy50

输出描述:

  • 输出一行一个数字表示最坏情况下需要多少次移动可以离开地牢,如果永远无法离开,输出 -1。以下测试用例中,牛牛可以上下左右移动,在所有可通行的位置.上,地牢出口如果被设置在右下角,牛牛想离开需要移动的次数最多,为3次。

输入示例:

3 3
...
...
...
0 1
4
1 0
0 1
-1 0
0 -1

输出示例:

3

解题思路

题目难点

  • 清楚的理解题目意思,其中出口是任意可到达的坐标点, 因此需要求出出发点到达任意出口点的最少步数。最后取最大的那个出口做为答案。
  • 如何利用行走方式列表,该列表是判断其它坐标点是否是当前位置周围点的条件(BFS广度优先算法)
  • 充分理解广度优先算法的实际应用(BFS实际上是一种逐层向外扩张的算法)
  • 如何避免无限迭代(设置一个访问过的标志位即可)
  • 该题目中的坐标轴和平时所遇到的坐标轴不一样

问题图解

地牢逃脱坐标系统

地牢逃脱坐标系统


地牢逃脱问题示意图

地牢逃脱问题示意图


广度优先算法图示

地牢逃脱BFS


代码

#include <iostream>
#include <utility>
#include <vector>
#include <queue>

using namespace std;

class Point;

// 全局变量初始化
static vector< vector<Point> > grid;        // 坐标网格
static queue<Point> help_queue;             // 辅助队列
static vector< pair<int, int> > methods;    // 行走方式列表
static unsigned int n = 0;   // 坐标网格的x长度
static unsigned int m = 0;   // 坐标网格的y长度
static unsigned int k = 0;   // 行走方式的种数

class Point
{
// 成员变量
public:
    int     x;      // 坐标点的x坐标
    int     y;      // 坐标点的y坐标
    int     step;   // 从出发点到达该坐标点所花费的步长
    char    reachable;  // 是否可到达
    bool    visited;    // 是否访问过

public:

    Point():x(0), y(0), step(-1), reachable('.'), visited(false){}
    // 类方法判断一个位置(x, y)是否合法(不超过边界)
    static bool isValid(int x, int y)
    {
        if( x < 0 || x >= n || y < 0 || y >= m)
            return false;
        else
            return true;
    }

    // 判断一个坐标点的位置是否可以到达
    bool isReachable()
    {
        if( reachable == 'X')
            return false;
        else
            return true;
    }

    // 判断一个坐标点的位置是否访问过
    bool isVisited()
    {
        return visited;
    }

    void pushArround()
    {
        // 下一步坐标点的位置(next_x, next_y)
        int next_x, next_y;

        // methods是行走方式列表
        // methods[idx]为其中一种行走方式
        // methods[idx].first是行走方式的x位移
        // methods[idx].second是行走方式的y位移
        for(unsigned int idx=0; idx < k; ++idx)
        {
            next_x = x + methods[idx].first;
            next_y = y + methods[idx].second;

            if( isValid(next_x, next_y)
                && grid[next_x][next_y].isReachable()
                && !grid[next_x][next_y].isVisited()){

                grid[next_x][next_y].step = step+1;     // 下一步坐标点所花费的步数 = 当前坐标点所花费的步数+1
                grid[next_x][next_y].visited = true;    // 下一步坐标点设置为访问过
                help_queue.push(grid[next_x][next_y]);  // 压入辅助队列
            }

        }
    }
};


int main()
{
    cin >> n >> m;
    // 生成n * m 二维网格
    grid.resize(n);
    for(unsigned int idx=0; idx < n; ++idx){
        grid[idx].resize(m);
    }

    // 输入坐标点是否可达
    for(unsigned int idx_x=0; idx_x < n; ++ idx_x){
        for(unsigned int idx_y=0; idx_y < m; ++idx_y){
            cin >> grid[idx_x][idx_y].reachable;
            grid[idx_x][idx_y].x = idx_x;
            grid[idx_x][idx_y].y = idx_y;
        }
    }


    // 输入出发点的坐标(x0, y0)
    int x0, y0;
    cin >> x0 >> y0;

    // 设置出发点的属性,并在迭代之前将其压入队列
    grid[x0][y0].step = 0;
    grid[x0][y0].visited = true;
    help_queue.push(grid[x0][y0]);

    // 输入行走方式的列表
    cin >> k;
    for(unsigned int idx=0; idx < k; ++idx){
        int dx, dy;
        cin >> dx >> dy;
        methods.emplace_back(dx, dy);
    }

    // 开始BFS算法
    while( !help_queue.empty() ){
        Point temp_point = help_queue.front();
        help_queue.pop();
        temp_point.pushArround();
    }

    // 遍历整个坐标网格得出结果
    int result = 0;
    for(unsigned int idx_x=0; idx_x < n; ++idx_x){
        for(unsigned int idx_y=0; idx_y < m; ++idx_y){

            if(grid[idx_x][idx_y].isReachable() ){
                if(grid[idx_x][idx_y].step==-1){
	                // 如果存在出口永远不可到达,则直接跳出两层循环
                    result = -1;
                    idx_x = n;
                    break;
                } else {
	                // 否则则取所花费步数最长的那个出口
                    result = max(result, grid[idx_x][idx_y].step);
                }
            }
        }
    }

    cout << result << endl;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值