链接:http://acm.hust.edu.cn/vjudge/problem/15200
/*
translation:
先沿着左边的墙从 S 一直走,求到达 E 的步数。
再沿着右边的墙从 S 一直走,求到达 E 的步数。
最后求最短路。
solution:
最短路好求。重点是前两步!
很容易想到前两步用简单的dfs就可以求出。但是关键是要“沿着墙壁走”!
观察可以发现规律:设当前游戏者朝向为d,则沿着右边墙走时候的检索顺序肯定为d的右边,d,d的左边,d相反的
方向。沿着左边墙壁走的策略类似,根据这个规律即可写出程序。详见dfs方法中的注释。
note:
1:原来dfs写法是定义一个全局变量ans,然后在每次递归调用时ans++,碰到最终点是返回return语句。但其实
return为空时会爆栈!!因为只有这一层结束递归,返回上一层后由于上一层没有结束方法的语句,还是会继续递
归执行,导致爆栈!
2:这种获得初始朝向的写法是错误的,我觉得逻辑上没问题,不知道错在哪??
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 40 + 5;
const int N = 3;
const int S = 1;
const int E = 0;
const int W = 2;
char G[maxn][maxn];
int w, h, ans, vis[maxn][maxn];
int end_row, end_col;
int dir_row[] = {0, 1, 0, -1};
int dir_col[] = {1, 0, -1, 0};
struct Step {
int r, c, dis;
Step(int r = 0, int c = 0, int dis = 0) : r(r), c(c), dis(dis) {}
};
inline bool inside(int r, int c) {
return r >= 0 && r < h && c >= 0 && c < w;
}
int dfs(int dir, int side, int r, int c, int ans) {
//dir:当前朝向 side:靠左/右墙走 r,c:当前位置 ans:步数
int nr, nc;
dir = (dir+4-side)%4; //找到要开始的那个方向,注意加上4是为了让结果不小于0
for(int d = 0; d < 4; d++) {
nr = r + dir_row[dir];
nc = c + dir_col[dir];
if(nr == end_row && nc == end_col) return ans+1; //note1
if(inside(nr, nc) && G[nr][nc] != '#')
return dfs(dir, side, nr, nc, ans+1);
dir = (dir+4+side)%4; //根据side来求下一个要检索的方向
}
}
void bfs(int sr, int sc) {
memset(vis, 0, sizeof(vis));
queue<Step> q;
q.push(Step(sr, sc, 1));
vis[sr][sc] = 1;
while(!q.empty()) {
Step u = q.front(); q.pop();
if(u.r == end_row && u.c == end_col) {
printf("%d\n", u.dis);
return;
}
for(int d = 0; d < 4; d++) {
int nr = u.r + dir_row[d];
int nc = u.c + dir_col[d];
if(G[nr][nc] != '#' && !vis[nr][nc] && inside(nr, nc)) {
vis[nr][nc] = 1;
q.push(Step(nr, nc, u.dis+1));
}
}
}
}
int main()
{
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &w, &h);
for(int i = 0; i < h; i++) scanf("%s", G[i]);
int start_row, start_col;
for(int i = 0; i < h; i++) {
for(int j = 0; j < w; j++) {
if(G[i][j] == 'S') {
start_row = i; start_col = j;
}
if(G[i][j] == 'E') {
end_row = i; end_col = j;
}
}
}
//获得初始的朝向
int d;
if(start_row == 0) d = 1; //note2
if(start_row == h-1) d = 3;
if(start_col == 0) d = 0;
if(start_col == w-1) d = 2;
/*
原来获得初始朝向的写法,错误!!
for(d = 0; d < 4; d++) {
int nr = start_row + dir_row[d];
int nc = start_col + dir_col[d];
if(G[nr][nc] && inside(nr, nc)) break;
}
*/
//1表示沿着左边墙壁走,-1表示沿着右边墙壁走
printf("%d ", dfs(d, 1, start_row, start_col, 1));
printf("%d ", dfs(d, -1, start_row, start_col, 1));
bfs(start_row, start_col);
}
return 0;
}