HDU-1010 Tempter of the Bone(dfs+剪枝)

这里是题目链接

Tempter of the Bone

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 169633    Accepted Submission(s): 45019

 

Problem Description

The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze began to shake, and the doggie could feel the ground sinking. He realized that the bone was a trap, and he tried desperately to get out of this maze.

The maze was a rectangle with sizes N by M. There was a door in the maze. At the beginning, the door was closed and it would open at the T-th second for a short period of time (less than 1 second). Therefore the doggie had to arrive at the door on exactly the T-th second. In every second, he could move one block to one of the upper, lower, left and right neighboring blocks. Once he entered a block, the ground of this block would start to sink and disappear in the next second. He could not stay at one block for more than one second, nor could he move into a visited block. Can the poor doggie survive? Please help him.

 

Input

The input consists of multiple test cases. The first line of each test case contains three integers N, M, and T (1 < N, M < 7; 0 < T < 50), which denote the sizes of the maze and the time at which the door will open, respectively. The next N lines give the maze layout, with each line containing M characters. A character is one of the following:

'X': a block of wall, which the doggie cannot enter;
'S': the start point of the doggie;
'D': the Door; or
'.': an empty block.

The input is terminated with three 0's. This test case is not to be processed.

 

Output

For each test case, print in one line "YES" if the doggie can survive, or "NO" otherwise.

 

Sample Input

 

4 4 5

S.X.

..X.

..XD

....

3 4 5

S.X.

..X.

...D

0 0 0

 

Sample Output

 

NO

YES

先说一下题意,你落入了一个迷宫里,T秒后迷宫的大门会打开,你要从起点走到终点,还不能走重复的道路,并且要恰好在第T秒到达终点,才能出去,来到终点早了晚了都不行。给你地图的分布,问你能不能恰好走出这个迷宫。

这道题和以往的题不一样,以前是在时间限制内走到迷宫出口即可,现在是恰好在规定的时间到达,要求就有点苛刻

一开始也是用dfs跑的,但是会被TLE,就只能想法剪枝

首先想到的剪枝就是最短路径的剪枝  最短的路径当然是 没有任何障碍物的时候,横平竖直的走,即最短距离为 

abs(ex-sx)+abs(ey-sy),如果这个距离小于T的话,那么很明显,你因为不能在规定时间内走到迷宫出口而挂掉

再一个就是 计算一下除去墙壁后迷宫可以走的面积的大小,如果小于T的话,肯定会因为时间剩余而无路可走,这里很坑的一点就是     m*n-wall<=T    这个等号是可以取到的,因为起点是不消耗时间的,在我的代码里这一个等号节省了234ms,还是比较可观的。

另一个剪枝打死也没想到啊,就是传说中的 奇偶剪枝,关于奇偶剪枝,有必要学习一下

自己比较鄙陋的见解   就是你剩余的时间和路径的最短距离的奇偶性是相同的。因为无论你怎么走,你把路径和最短的路径比较的话,它总是差了那么个偶数

sta          
   
↑↓      
→↓ ↑→ end
       

如图所示,红色的是最短路径,黑色的是任意走的路径(你还可以再随机一点),我们把它将随机路径平移到和最短路径相同的道路上,我们就可以发现他一定会经过所有的最短路径,并且会比最短路径多出来偶数个长度,(个人理解是因为始终你都要经过最短路径,无论是上下左右,你都会走上去再拐回来,构成一个相互抵消的效果,不然就会偏离最短路径了),的确是不容易想到啊

剩余的就是dfs跑图代码了,至于为什么不用bfs,因为bfs往往找到的是耗时最少的路径,和我们的要求有点差距

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int mm = 9;

int book[mm][mm];
char mp[mm][mm];
int n, m, t;
int sx, sy, ex, ey;
int step = 0;
int wall = 0;
int to[4][2] = { 0,1,1,0,0,-1,-1,0 };

int flag = 0;
void dfs(int x, int y, int step) {
	if (x == ex && y == ey && step == t) {
		flag = 1;
		return;
	}
	if (flag)
		return;
	int temp = t - step - (abs(x - ex) + abs(y - ey));//奇偶判重 
	if (temp < 0 || temp % 2 == 1)
		return;
	for (int i = 0; i < 4; i++) {
		int nx = x + to[i][0];
		int ny = y + to[i][1];
		if (book[nx][ny] || nx < 0 || nx >= n || ny < 0 || ny >= m)
			continue;
		book[nx][ny] = 1;
		dfs(nx, ny, step + 1);
		book[nx][ny] = 0;
	}
}

void init() {
	step = 0;
	wall = 0;
	flag = 0;
	for (int i = 0; i < mm; i++)
		for (int j = 0; j < mm; j++)
			book[i][j] = 0;
}

int main()
{
	while (cin >> n >> m >> t) {
		if (!n && !m && !t)break;
		init();
		for (int i = 0; i < n; i++) {
			cin >> mp[i];
			for (int j = 0; j < m; j++) {
				if (mp[i][j] == 'S') {
					sx = i;
					sy = j;
				}
				if (mp[i][j] == 'D') {
					ex = i;
					ey = j;
				}
				if (mp[i][j] == 'X') {
					book[i][j] = 1;
					wall++;
				}
			}
		}
		if (n * m - wall <= t) {//空格数小于时间数  
			cout << "NO" << endl;
			continue;
		}
		book[sx][sy] = 1;//!!!!!
		dfs(sx, sy, 0);
		if (flag)cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章