数据范围 n,m<=40;
比赛想法:
感觉好麻烦,转来转去的,恶心死了;
归根到底,是这种题目写的太少,还有不够静下心来。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
using namespace std;
const int maxn = 100+10;
int dx[] = {0, -1, 0, 1};
int dy[] = {-1, 0, 1, 0};
int dl[][2] = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}};
int dr[][2] = {{0, 1}, {-1, 0}, {0, -1}, {1, 0}};
int sx, sy, ex, ey, n, m;
char G[maxn][maxn];
struct Pos { int x, y, s; };
int dfs(int x, int y, int d, int step, int dir[][2]) {
for(int i=0; i<4; i++) {
int j = ((d+3)%4+i)%4;
int nx = x+dir[j][0];
int ny = y+dir[j][1];
if(nx == ex && ny == ey) return step+1;
if(nx < 0 || ny < 0 || nx > n || ny > m) continue;
if(G[nx][ny] == '#') continue;
return dfs(nx, ny, j, step+1, dir);
}
}
int BFS(int sx, int sy) {
bool vis[maxn][maxn];
memset(vis, false, sizeof(vis));
queue<Pos> Q;
Q.push((Pos){sx, sy, 1});
vis[sx][sy] = true;
while(!Q.empty()) {
Pos p = Q.front(); Q.pop();
if(p.x == ex && p.y == ey) return p.s;
Pos np;
for(int d=0; d<4; d++) {
np.x = p.x + dx[d];
np.y = p.y + dy[d];
np.s = p.s + 1;
if(np.x < 0 || np.x > n || np.y < 0 || np.y > m) continue;
if(vis[np.x][np.y]) continue;
if(G[np.x][np.y] != '#') {
vis[np.x][np.y] = true;
Q.push(np);
}
}
}
return -1;
}
int main() {
int d1, d2;
scanf("%d%d", &m, &n);
for(int i=0; i<n; i++) {
scanf("%s", G[i]);
for(int j=0; j<m; j++) {
if(G[i][j] == 'S') {
sx = i; sy = j;
} else if(G[i][j] == 'E') {
ex = i; ey = j;
}
}
}
if(sx == 0) {
d1 = 3; d2 = 3;
} else if(sx == n-1) {
d1 = 1; d2 = 1;
} else if(sy == 0) {
d1 = 2; d2 = 0;
} else if(sy == m-1) {
d1 = 0; d2 = 2;
}
printf("%d\n", dfs(sx, sy, d1, 1, dl));
printf("%d\n", dfs(sx, sy, d2, 1, dr));
printf("%d\n", BFS(sx, sy));
return 0;
}
题解:
如果是正常人的话,那就是最普通的bfs;只不过结构体里再存一个步数罢了。
至于左撇子盲人和右撇子盲人呢,就按照他的规则来走就好了。
这道题的难点就是静下心来,排出坐标的转换。
这里用了两个d1,d2,存储人的朝向,实际上两个不管是左撇子,右撇子,他们的朝向都是一样的。
但是因为他们转的方向不一样,所以他们的方向数组顺序也就不一样,所以同一个朝向在数组里的位置也不一样,所以d1,d2也就不一样.
同时,需要注意的是,竖轴是x,横轴是y,而且如果往上走,应该是x-1,y不变,即{-1,0},其余的也同理。
还有,则是这道题的题意没有给的很清晰,也就是初始的点只可能在矩形的四条边上,因为初始的点即房间的门~
整个程序里有两步比较关键:
1,
int dl[][2] = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}};
int dr[][2] = {{0, 1}, {-1, 0}, {0, -1}, {1, 0}};
上面的数组是左撇子的,取当前朝向的前一个开始,往后数四个。
就比如现在的d1是1,也就是当前的方向是往上的,那么就是从下标0开始再到3;因为先看左边是否可以走,如果左边不能走就看当前朝向能不能走,如果左边上面都堵了,就只能往右,如果右边也堵了,就只能原路返回了。实际上就是模拟了这么一个过程。
2,
int j = ((d+3)%4+i)%4;
就是在草稿纸上推一下,
这样的公式才能使初始位置是当前朝向的前一个下标。