题目链接:P1126 机器人搬重物
这题WA了3次,第四次才AC,卡了卡了好几个小时
第一次:30分 第二次 :80分 第三次 90分 第四次100分
这题有个难处理的地方在于障碍物占了一个格子,而机器人只能走在格子的边线上,我们仍然把机器人按照正常的格子去走。
注意,题意给的是n*m个方格,也就是拥有(n+1)*(m+1)格点,这些格点是机器人可以走的。所以这里[0,n]这个区间机器人都是可以走的,但由于机器人的体积,0和n都不能走,因此区间变为开区间(0,n)
我们这样来处理一个有障碍物的方格,对于坐标为x,y的障碍物,我们认为它的左上部分(x-1,y),(x,y-1),(x-1,y-1)都是有障碍物的,即一个有障碍物的方格的四个点都标记为障碍,这与我们的格点是不矛盾的。
机器人走的是格点,而障碍物占据的确是一个方格,即为4个格点,我们按照坐标来读入障碍物,然后把障碍物的左上部分标记为障碍,这四个标记为障碍的格点即代表了这个障碍物(这里不理解的可以思考一下)
所以我们判断机器人下一步要走的格子能不能走不仅要判断(x,y)这个点是否为1,还要判断(x+1,y),(x,y+1),(x+1,y+1)这三个点是否为1,这里和我刚刚说的标记左上部分是并不矛盾的,因为(x,y)这个点属于这三个点左上部分,这三个点中任何一个点为1,都能导致(x,y)不能走,因为一个为障碍物的点左上部分被标记为障碍了,所以我们要判断4个点。
这样机器人有障碍物的位置关系就处理好了,下面还有要注意的地方,也就是我wa的原因
1:机器人每次可以走1步,2步,或者3步,我们按照1,2,3,的顺序进行bfs,如果当第一步或者第二步我们已经判断它不能走,那么我们就要break,举个例子说一下
比如说 0 0 1 0 0 0是我们读入的数据中的3个格点,机器人在左边黄色的0,机器人要往右走,我们首先判断第一步和第二步能不能走,显然第一步和第二步都有障碍不能走,但是第三步呢,却能走,所以这就出现了机器人跳过障碍物的情况,我们显然是不允许这样的,因此当我们判断第一步或者第二部有障碍的时候就break,注意是有障碍的时候才break,如果是vis数组标记过了导致不能走,我们不能break
2:要注意边界,由于机器人的体积,0和n都是不行的,
几次错误我都是往结构体加了一个vector来记录机器人的路径,才找到的错误的,这个方法挺不错的
#include<bits/stdc++.h>
using namespace std;
const int d[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };//朝向:0表示朝上 1下 2左 3右
const int r[4][2] = { { 2, 3 }, { 3, 2 }, { 1, 0 }, { 0, 1 } };//每个方向左右旋转变化后的方向
int n, m, a[55][55];
bool vis[55][55][4];
typedef pair<int, int> pp;
struct P{
int x, y, f, t;
//vector<pp> v;//这个可以记录路径
P(int _x = 0, int _y = 0, int _f = 0, int _t = 0) :x(_x), y(_y), f(_f), t(_t){}
};
queue<P> que;
int sx, sy, gx, gy, sf;
char c;
bool valid(int x, int y)
{
return x > 0 && y > 0 && x < n&&y < m&&a[x][y] != 1 && a[x + 1][y] != 1 && a[x][y + 1] != 1 && a[x + 1][y + 1] != 1;
}
void bfs()
{
//vector<pp> sv;
//sv.push_back(pp(sx, sy));
que.push(P(sx, sy, sf, 0));
vis[sx][sy][sf] = true;
while (!que.empty())
{
P cur = que.front();
que.pop();
if (cur.x == gx&&cur.y == gy)
{
cout << cur.t << endl;
return;
}
int x = cur.x, y = cur.y, f = cur.f, t = cur.t;
//vector<pp> v = cur.v;
for (int j = 1; j <= 3; j++)
{
int nx = x + d[f][0] * j, ny = y + d[f][1] * j;
if (valid(nx, ny) && !vis[nx][ny][f])
{
vis[nx][ny][f] = true;
//v.push_back(pp(nx, ny));
que.push(P(nx, ny, f, t + 1));
//v.pop_back();
}
else if (!valid(nx, ny))//注意
break;
}
for (int i = 0; i < 2; i++)
{
if (!vis[x][y][r[f][i]])
{
vis[x][y][r[f][i]] = true;
que.push(P(x, y, r[f][i], t + 1));
}
}
}
cout << -1;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> a[i][j];
}
}
scanf("%d%d%d%d %c", &sx, &sy, &gx, &gy, &c);
if (c == 'E') sf = 3;
else if (c == 'W') sf = 2;
else if (c == 'S') sf = 1;
else sf = 0;
bfs();
return 0;
}
还有下面一种处理障碍的方法,和上面差不多,到时候我们可以直接判断a[x][y]!=2就是能走
for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (a[i][j] == 1) { a[i][j] = a[i - 1][j] = a[i][j - 1] = a[i - 1][j - 1] = 2;//到时候我们可以直接判断a[x][y]!=2就是能走 } } }