摇骰子走步数--压缩为一维空间的bfs最短路径

题目

一个N * N的棋盘,起点是左下角,一次可以走 1-6步
从左下角开始棋盘编号从下往上蛇形递增
7 8 9
6 5 4
1 2 3
如上图(其实不是图)所示:
起点是 1,终点是 9(N*N) (1-9为棋盘编号)
每格棋盘单元格内容一般是-1
如果棋盘单元格内容不是-1,而是一个数字,
则如果跳到这里,就要传送到指定数字编号的棋盘单元格中
-1 -1 -1
-1 -1 -1
-1 -1 8
如图:走到第三个格的位置,就会自动被传送到8的位置

问:到终点的最少次数?
注意:如果传送到的棋盘单元格内容也不是-1,无法进行二次传送

题目解析

  • 看起来实际上就两步:
  1. 把二维数组转一维,从下往上之字形遍历即可.
  2. 广度优先搜索找到最先到终点的位置.

然而我…:
在这里插入图片描述

  • 个人总结的坑点:
  1. 转一维的坑点:是从最后一行开始转的,并且长度为奇偶都得分开讨论。
  2. 写扩散的坑点:如果你像我一样是通过判断扩散出的元素来找终点的话,那么这个点着实是坑,由于扩散入队的元素形式有两种,你又得分开讨论了。如果是直接从每次出队扩散的元素进行判断,那么这个坑点就是没有的。。。

解题代码

class Solution {
public:
//由于有传送门,可能将其传送回头,所以还是需要visit数组防止回头路
    int snakesAndLadders(vector<vector<int>>& board) {
        //把终点有传送门的直接pass
        if(board[0][0]!=-1)return -1;
        //先转一维数组(这样就不需要考虑遍历顺序这回事了)
        n = board.size();
        change(board);
        //以编号进行bfs(1~n*n)
        Q.push(1);
        visit.insert(1);
        //bfs模板
        int step = 0;
        while(!Q.empty()){
            for(int i=Q.size();i>0;i--){
                int t = Q.front();Q.pop();
                //根据t进行下一步扩散
                if(check(t))
                    return step+1;
            }
            step++;
        }
        return -1;
    }
private:
    queue<int>Q;
    vector<int>t_board;
    unordered_set<int>visit;
    int n;
    void change(vector<vector<int>>&board){
        t_board.resize(n*n+1);
        int index=0;
        for (int i = n-1; i >= 0; i--) {
            //取最下方为第一行,奇数行正向,偶数行反向
            int row=n - i;
            if(row % 2 ==1){
                for (int j = 0; j < n; j++) {
                    t_board[++index]=board[i][j];
                }
            }else{
                for (int j = n-1; j >= 0; j--) {
                    t_board[++index]=board[i][j];
                }
            }
        }
    }
    bool check(int t){
        for(int i=1;i<=6;i++){
            if(t+i>n*n)
                continue;
            if(t_board[t+i]!=-1&&!visit.count(t_board[t+i])){
                if(t_board[t+i]==n*n)return true;
                visit.insert(t_board[t+i]);
                Q.push(t_board[t+i]);
            }else if(t_board[t+i]==-1&&!visit.count(t+i)){if(t+i==n*n)return true;
                visit.insert(t+i);
                Q.push(t+i);
            }
        }
        return false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值