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;
}

 

 

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