题解 P1126 【机器人搬重物】
bigfish0214 · · 题解
一道bfs题,说一说实现细节吧。
-
首先要把图坐标转化为点坐标,如果这个点左上、左下、右上、右下有1,则机器人站不到该点,我用1表示站不上的点,0代表能站上。
-
然后是方向变换,下面用int变量d代表方向,0,1,2,3分别代表N,W,S,E,往左转的话就是(d+1)%4,往右转就是(d-1+4)%4。这样就省去了分为各种情况进行方向判断的麻烦操作。
-
最后是前进1~3步的情况,需要注意的是如果前进1步or2步到达的点越界或者该点值为1,则后面的点在当前步数一定到达不了,就不需要添加到队列了。需要区分的是如果1步or2步的点加上到达点后所在方向已经被访问过,则后面的点还需要考虑。
附上AC代码,可以注意下我对方向的处理。
#include <iostream>
#include <map>
#include <queue>
using namespace std;
struct robot {
int r;
int c;
int d;//0 N 1 W 2 S 3 E
};
int N, M;
int arr[55][55];
int sr, sc;
int er, ec;
char sd;
int vec[55][55];
bool vis[55][55][4];
map<char, int> ma;
int d1[4] = { -1,0,1,0 };
int d2[4] = { 0,-1,0,1 };
void init() {
ma['N'] = 0;
ma['W'] = 1;
ma['S'] = 2;
ma['E'] = 3;
for (int i = 1; i < N; i++) {
for (int j = 1; j < M; j++) {
if (arr[i - 1][j - 1] == 1 || arr[i - 1][j] == 1 || arr[i][j - 1] == 1 || arr[i][j] == 1) {
vec[i][j] = 1;
}
else {
vec[i][j] = 0;
}
}
}
}
int bfs() {
queue<robot> q;
robot rb = { sr, sc, ma[sd] };
vis[sr][sc][ma[sd]] = true;
q.push(rb);
int sum = 0;
while (!q.empty()) {
int len = q.size();
for (int i = 0; i < len; i++) {
rb = q.front();
q.pop();
if (rb.r == er && rb.c == ec) {
return sum;
}
int k = rb.d;
for (int j = 1; j <= 3; j++) {
int a = rb.r + d1[k] * j;
int b = rb.c + d2[k] * j;
if (a < 1 || a >= N || b < 1 || b >= M || vec[a][b] == 1) {
break;
}
if (vis[a][b][k]) {
continue;
}
robot rot = { a,b,k };
vis[a][b][k] = true;
q.push(rot);
}
int dr = (k - 1 + 4) % 4;
if(!vis[rb.r][rb.c][dr]){
vis[rb.r][rb.c][dr] = true;
q.push({ rb.r,rb.c,dr });
}
dr = (k + 1) % 4;
if (!vis[rb.r][rb.c][dr]) {
vis[rb.r][rb.c][dr] = true;
q.push({ rb.r,rb.c,dr });
}
}
sum++;
}
return -1;
}
int main()
{
cin >> N >> M;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
cin >> arr[i][j];
}
}
cin >> sr >> sc >> er >> ec >> sd;
init();
cout << bfs();
return 0;
}