洛谷P1126题解(真滴通俗易懂)

第二次写题解QAQ!!!

传送门:P1126 机器人搬重物 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

拿到题目已读题,哇!好简单,拿去提交后WAWAWAWA...

再看一遍题,坑点真**多。

分析一下

坑点1:机器人不是在格子上走,而是在格点上走,这就导致n和m都得++(不懂数一遍)

坑点2:   这个败家机器人是有宽度的,又因为一个障碍物占了四个点(这也算个坑),所以这破机器人不能在障碍物格子的四个点上走。

坑点3:机器人不能在边线上走!!!(改完后提交80分就是这原因)

这上面是几个大坑点,还有几点小问题---

1、nx,ny,fx,fy都得++。(与n和m同理)

2、vis(是否重复走的数组)要开成三维:int vis[i][j][k]!!!

这表示当在i行j列面向k时是否重复。

k=0表示上

k=1表示下

k=2表示左

k=3表示右

ok先贴上代码,代码中详细解读一下:

#include<bits/stdc++.h>

int n, m, sx, sy, fx, fy, sdir, mp[60][60], vis[60][60][4];
//行 列 初始x,y 结束x,y 初始方向 mp地图
int drive[4][3][2]{-1, 0, -2, 0, -3, 0, 1, 0, 2, 0, 3, 0, 0, -1, 0, -2, 0, -3, 0, 1, 0, 2, 0, 3};
//这个drive[i][j][k]表示往i方向走j格时x和y的变更(j仅仅是下标,真正走的是drive[i][j]里面的步数)
int turnR[4]{3, 2, 0, 1}, turnL[4]{2, 3, 1, 0};//往左和往右
//栗子:turnR[3]表示往右转变成turnR[3]-->1,1表示往上
//注意以上转向都是以机器人视角来讲的
struct Node {
    int x, y, time, dir;//x和y 时间和此时面朝方向
};

void bfs() {
    std::queue<Node> q;
    q.push({sx, sy, 0, sdir});//正常入队列
    vis[sx][sy][sdir] = 1;//初始点标记
    while (!q.empty()) {
        Node tmp = q.front();
        q.pop();
        if (tmp.x == fx && tmp.y == fy) {
            std::cout << tmp.time;
            return;
        }
        /*以上好理解*/
        for (int i = 0; i < 3; i++) {//三种方式~~~
            int nx = tmp.x + drive[tmp.dir][i][0], ny = tmp.y + drive[tmp.dir][i][1];//移动
            if (nx > n || nx < 1 || ny > m || ny < 1 || mp[nx][ny])break;
            //非法越界,因为我们是按步数从小往大遍历,如果这个不行,那么以后也肯定越界(因为此时方向一致)
            if (vis[nx][ny][tmp.dir])continue;//走过就continue
            vis[nx][ny][tmp.dir] = 1;//标记走过
            q.push({nx, ny, tmp.time + 1, tmp.dir});//入队列
        }
        int L = turnL[tmp.dir], R = turnR[tmp.dir];//转向
        if (!vis[tmp.x][tmp.y][L])vis[tmp.x][tmp.y][L] = 1, q.push({tmp.x, tmp.y, tmp.time + 1, L});
        if (!vis[tmp.x][tmp.y][R])vis[tmp.x][tmp.y][R] = 1, q.push({tmp.x, tmp.y, tmp.time + 1, R});
    }
    std::cout << -1;
}

void init() {
    for (int i = 1; i <= m; i++)
        vis[1][i][0] = 1, vis[1][i][1] = 1, vis[1][i][2] = 1, vis[1][i][3] = 1, vis[n][i][0] = 1, vis[n][i][1] = 1, vis[n][i][2] = 1, vis[n][i][3] = 1;
    for (int i = 2; i < n; i++)
        vis[i][1][0] = 1, vis[i][1][1] = 1, vis[i][1][2] = 1, vis[i][1][3] = 1, vis[i][m][0] = 1, vis[i][m][1] = 1, vis[i][m][2] = 1, vis[i][m][3] = 1;
}

int main() {
    char tmp;//初始方向
    std::cin >> n >> m;//读入
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            int goods;//"mp[i][j]"是什么东东
            std::cin >> goods;
            if (goods)mp[i][j] = goods, mp[i][j + 1] = goods, mp[i + 1][j] = goods, mp[i + 1][j + 1] = goods;
            //这上面是对障碍物的初始化,注意占掉四个格点!!!
        }
    std::cin >> sx >> sy >> fx >> fy >> tmp;//读入
    n++, m++, sx++, sy++, fx++, fy++;//这里一定记得++哦,不然就boom
    switch (tmp) {//将初始方向转化成数字:上下左右分别表示0 1 2 3
        case 'E':
            sdir = 3;
            break;
        case 'S':
            sdir = 1;
            break;
        case 'W':
            sdir = 2;
            break;
        case 'N':
            sdir = 0;
    }
    init();//这个函数是对vis的初始化,因为不能走边界,所以得将vis的边界标记为走过
    bfs();//正常bfs
}

蒟蒻三天心血奉上,点个👍呗!!!

--END--

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值