第二次写题解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--