poj-3083

31 篇文章 0 订阅
// 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的)来用,还是对它的本质认识不够清楚.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值