// 700K 0MS G++
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
#define MAX 50
char maze[MAX][MAX];
char leftFirst[2] = {-1, 1};
char rightFirst[2] = {1, -1};
struct Point {
int x;
int y;
int distance;
};
typedef struct Point Point;
queue<Point> BFSQueue;
char BFSFlag[MAX][MAX];
char DFSFlag[MAX][MAX];
int W;
int H;
int Sx;
int Sy;
int Ex;
int Ey;
char reachE;
int distanceSum;
//direction : 0 up 1 right 2 down 3 left
int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int leftDFS(int curX, int curY, char * checkProcedure, int distance, int direction) {
// printf("leftDFS %d %d\n", curX, curY);
// printf("DFS %d %d\n", curX, curY);
distanceSum++;
if (curX == Ex && curY == Ey) {
return distance;
}
int passTime = 0;
int newX = curX;
int newY = curY;
newX = curX + dir[(4 + direction-1)%4][0];
newY = curY + dir[(4 + direction-1)%4][1];
// getLeft(curX, curY, &newX, &newY, direction);
if (newX >=0 && newX <= W-1 &&
newY >= 0 && newY <= H-1 &&
maze[newY][newX] != '#') {
int newDistance = leftDFS(newX, newY, checkProcedure, distance + 1, (4 + direction-1)%4);
if (newDistance) {
return newDistance;
}
}
newX = curX + dir[(4 + direction)%4][0];
newY = curY + dir[(4 + direction)%4][1];
// getUp(curX, curY, &newX, &newY, direction);
if (newX >=0 && newX <= W-1 &&
newY >= 0 && newY <= H-1 &&
maze[newY][newX] != '#') {
int newDistance = leftDFS(newX, newY, checkProcedure, distance + 1, (4 + direction)%4);
if (newDistance) {
return newDistance;
}
}
// getRight(curX, curY, &newX, &newY, direction);
newX = curX + dir[(4 + direction+1)%4][0];
newY = curY + dir[(4 + direction+1)%4][1];
if (newX >=0 && newX <= W-1 &&
newY >= 0 && newY <= H-1 &&
maze[newY][newX] != '#') {
int newDistance = leftDFS(newX, newY, checkProcedure, distance + 1, (4 + direction+1)%4);
if (newDistance) {
return newDistance;
}
}
newX = curX + dir[(4 + direction+2)%4][0];
newY = curY + dir[(4 + direction+2)%4][1];
// getDown(curX, curY, &newX, &newY, direction);
if (newX >=0 && newX <= W-1 &&
newY >= 0 && newY <= H-1 &&
maze[newY][newX] != '#') {
passTime++;
int newDistance = leftDFS(newX, newY, checkProcedure, distance + 1, (4 + direction+2)%4);
if (newDistance) {
return newDistance;
}
}
return 0;
}
int rightDFS(int curX, int curY, char * checkProcedure, int distance, int direction) {
// printf("rightDFS %d %d\n", curX, curY);
distanceSum++;
if (curX == Ex && curY == Ey) {
// reachE = 1;
return distance;
}
int newX = curX;
int newY = curY;
int passTime = 0;
newX = curX + dir[(4 + direction+1)%4][0];
newY = curY + dir[(4 + direction+1)%4][1];
// getRight(curX, curY, &newX, &newY, direction);
if (newX >=0 && newX <= W-1 &&
newY >= 0 && newY <= H-1 &&
maze[newY][newX] != '#') {
int newDistance = rightDFS(newX, newY, checkProcedure, distance + 1, (4 + direction+1)%4);
if (newDistance) {
return newDistance;
}
}
newX = curX + dir[(4 + direction)%4][0];
newY = curY + dir[(4 + direction)%4][1];
// getUp(curX, curY, &newX, &newY, direction);
if (newX >=0 && newX <= W-1 &&
newY >= 0 && newY <= H-1 &&
maze[newY][newX] != '#') {
int newDistance = rightDFS(newX, newY, checkProcedure, distance + 1, (4 + direction)%4);
if (newDistance) {
return newDistance;
}
}
newX = curX + dir[(4 + direction-1)%4][0];
newY = curY + dir[(4 + direction-1)%4][1];
// getLeft(curX, curY, &newX, &newY, direction);
if (newX >=0 && newX <= W-1 &&
newY >= 0 && newY <= H-1 &&
maze[newY][newX] != '#') {
int newDistance = rightDFS(newX, newY, checkProcedure, distance + 1, (4 + direction-1)%4);
if (newDistance) {
return newDistance;
}
}
newX = curX + dir[(4 + direction+2)%4][0];
newY = curY + dir[(4 + direction+2)%4][1];
// getDown(curX, curY, &newX, &newY, direction);
if (newX >=0 && newX <= W-1 &&
newY >= 0 && newY <= H-1 &&
maze[newY][newX] != '#') {
int newDistance = rightDFS(newX, newY, checkProcedure, distance + 1, (4 + direction+2)%4);
if (newDistance) {
return newDistance;
}
}
return 0;
}
void processBFSNode(int x, int y, int distance) {
BFSFlag[x][y] = 1;
Point newPoint;
newPoint.x = x;
newPoint.y = y;
newPoint.distance = distance + 1;
BFSQueue.push(newPoint);
}
int BFS(int beginX, int beginY) {
while(BFSQueue.size()) {
BFSQueue.pop();
}
memset(BFSFlag, 0, sizeof(BFSFlag));
BFSFlag[beginX][beginY] = 1;
Point beginPoint;
beginPoint.x = beginX;
beginPoint.y = beginY;
beginPoint.distance = 1;
BFSQueue.push(beginPoint);
while(BFSQueue.size()) {
Point curPoint = BFSQueue.front();
BFSQueue.pop();
int curX = curPoint.x;
int curY = curPoint.y;
int curDistance = curPoint.distance;
//up
if (curY+1 <= H-1 && !BFSFlag[curX][curY+1]
&& maze[curY+1][curX] != '#') {
if (curX == Ex && curY + 1 == Ey) {
return curDistance+1;
} else {
processBFSNode(curX, curY+1, curDistance);
}
}
//down
if (curY-1 >= 0 && !BFSFlag[curX][curY-1]
&& maze[curY-1][curX] != '#') {
if (curX == Ex && curY - 1 == Ey) {
return curDistance+1;
} else {
processBFSNode(curX, curY-1, curDistance);
}
}
//left
if (curX-1 >= 0 && !BFSFlag[curX-1][curY]
&& maze[curY][curX-1] != '#') {
if (curX-1 == Ex && curY == Ey) {
return curDistance+1;
} else {
processBFSNode(curX - 1, curY, curDistance);
}
}
//right
if (curX+1 >= 0 && !BFSFlag[curX+1][curY]
&& maze[curY][curX+1] != '#') {
if (curX+1 == Ex && curY == Ey) {
return curDistance+1;
} else {
processBFSNode(curX + 1, curY, curDistance);
}
}
}
return -1;
}
void solve() {
// printf("%d %d %d %d\n", Sx, Sy, Ex, Ey);
memset(DFSFlag, 0, sizeof(BFSFlag));
distanceSum = rightDFS(Sx, Sy, rightFirst, 0, 0);
printf("%d ", distanceSum+1);
memset(DFSFlag, 0, sizeof(BFSFlag));
distanceSum = leftDFS(Sx, Sy, leftFirst, 0, 0);
printf("%d ", distanceSum+1);
printf("%d\n", BFS(Sx, Sy));
}
int main() {
int caseNum;
scanf("%d", &caseNum);
for (int i = 1; i <= caseNum; i++) {
scanf("%d %d", &W, &H);
memset(maze, 0, sizeof(maze));
for (int j = 0; j < H; j++) {
scanf("%s", maze[j]);
// printf("%s\n", maze[j]);
for (int k = 0; k < W; k++) {
if (maze[j][k] == 'S') {
Sx = k;
Sy = j;
} else if (maze[j][k] == 'E') {
Ex = k;
Ey = j;
}
}
}
solve();
}
}
真心被恶心到了,刷新了我对DFS题的看法,没想到一直用的DFSvisitedFlag在这里反而成了拦路虎.
初看觉得简单,意味所说的left/right走法就是简单的调整下DFS中考虑方向的顺序,但是在仔细的读题以后,发现不能满足需求。
因为按照这种走法,在走到一条死路以后,会直接直接回退到上一个分叉点来进行新方向的DFS,这就出现了问题,题目要求的是按照这种left/right的走法,在走出迷宫时
一共会走多少步,上面的直接回退等于没有把从死路回去走的步数计算进去,所以不能这么搞(一开始还勉强实现了把回退路算进去,但是这样DFS次数就很多,直接TLE,并且结果也不不全对)。
题目所说的left/right走法指得是 一种经典的迷宫走法(但是只适用于出口在迷宫边上的情况,题目也专门说明了不会出现这个情况), 就是一直沿着自己面向方向的left/right侧的墙行走,就一定可以走出迷宫。如何模拟这种走法也需要一些功夫,因为需要一个重要的信息:在当前格子中的面朝的方向,这样才能沿着自己的left/right侧方向前进,
并且还有麻烦的一点,就是要维护一套相对方向与绝对方向, 即当前是面朝 绝对左边,但这时候如果要向 相对左边 走的话,真正的绝对方向(为了计算位置的x,y坐标)是左边再向左转,真正的方向就是下方(绝对方向, 位置坐标的y-1),以left做法为例:DFS的方向顺序应该是:先优先向左走,不能向左走再向上走, 不能向上走再向右走,
最后才向后走(注意这里的转向都是相对转向, 并且都有路可走),这样就保证了一定是沿着自己left侧的墙在前行,
e.g对于这个图:
# # # # # E #
# 6 7 8 9 10 #
# 1 2 3 4 5 #
# # # S # # #
在S处,只能向上走,走到3, 这时候 朝向:上,
然后优先向左转(绝对上向左转 就是 绝对向左),走到2,朝向:左
在2 只能向上走(注意,这里的上是针对当前的 朝向 左 来说的, 绝对方向是 左),走到1,朝向: 左
在1只能向右走(右相对于朝向左来说,绝对方向是上 ), 走到6, 朝向: 上
然后在6 只能向右走(右相对于左朝向,绝对方向也是右),走到 7, 朝向:右
在7只能向上走(上相对于右朝向, 绝对方向是右),走到8,朝向 右.
.........................
这里的方向转换整的很烦人,一开始还搞了不少辅助函数,后来发现这么搞就很简单了:
首先规定 这样的方向映射:
0->上
1->右
2->下
3->左
那么在某个朝向 E 向 F走 以后的绝对方向就是 (E +F)%4
比如, 朝向上 E = 0, 向左走 F = 3就是 (0+3)%4 = 3 (左)
朝向 右, 向上走就是 (1+0)%4 = 1(右)
朝向下,向左走就是(2 + 3) % 4 = 1(右)
光这样,还会有一个问题:
######## #......# #.####.# #.####.# #.####.# #.####.# #...#DF# #S#E####对于上面这个图,按照left走法,走到D处以后,就没有路可走了,虽然D的右边F不是墙,但是因为DFSVisitedFlag标示了F被遍历过了,
不能再走到F,因此在D无路可走了,left走法走不出迷宫了,解决办法也简单,去掉DFSVisitedFlag就可以了,传统的DFS不允许走已经经过的点,
但是本题不一样,是可以走已经走过的点的(只要一直按照靠left走的走法走,就没问题,)题目保证了E在这种情况下是可达的,因此去掉Flag不会导致无限调用,
其实可以发现,left走法只是千百条DFS遍历路径中的一条(因此最后花的时间也少),但是这一条可以达到终点。right的同理。要注意的是,因为输入的是从maze的最上一行开始输入的,因此,直接根据输入构造出的迷宫其实是一个和真正maze上下颠倒的迷宫,因此,left/right走法要互换。
最后第3的值最短路,直接BFS求出就可以,这也是这道题最简单的部分了。
实在没想到,DFS还能这样离开FLAG(发现这一点似乎没有人吐槽,是我太愚钝了么, 算导上的DFS标准流程是需要染色color做flag的)来用,还是对它的本质认识不够清楚.