HDU 1010 Tempter of the Bone 骨頭的誘惑

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

一隻小狗受骨頭的誘惑進入了一個迷宮,初始時刻爲0,小狗每走一步時間+1,迷宮的門只有在t時刻的時候打開一下,問小狗能不能走出迷宮(t時刻剛好到達迷宮的門)。‘S’表示小狗初始位置,‘D’表示門到的位置,‘.’表示空地(可行走),‘X’表示牆(不能行走)。每個位置只能行走一次。

這題還是用DFS做,但要轉個彎。
剛開始直接做超時了三四次,然後去百度,學到了一招奇偶性剪枝,也就是我說的那個彎。
我這裏簡單說一下奇偶性剪枝。
地圖上某點座標爲(x,y),如果x+y爲奇數,這個點就是奇數點,x+y爲偶數,這個點就是偶數點。
地圖上奇偶點總是交替存在的,如下圖,我用0表示偶數點,1表示奇數點:
0 1 0 1 
1 0 1 0
0 1 0 1
1 0 1 0

如果小狗從偶數點出發,時間t就相當於它走的步數,如果走偶數步的話,只能到達偶數點。這時候如果門在奇數點,小狗就永遠不能剛好在t時刻停在門。這時候就沒必要進行DFS,進行了一次剪枝。在其他的奇偶位置也同理。

然後是代碼:

#include<stdio.h>  
#include<string.h>  
#include<iostream>  
using namespace std;
#define MAX 1005
char mpt[MAX][MAX];
int vis[MAX][MAX];
int a,b,time,ans;//ans用於標記是否確定能出去
int turn[4][2] = { 0, -1, 0, 1,  1, 0, -1,0};
void DFS(int x,int y,int t)
{
	if (ans)return;
	if (t == 0){
		if (mpt[x][y] == 'D')//t剩餘0,並且當前剛好在D上,ans=1,能出去
		{
			ans = 1;
		}
			return;//不管能不能出去,此時t已經等於0了,門只打開一下,繼續走以及沒用了,所以直接返回
	}
	int ty, tx;
	int i;
	for (i = 0; i < 4; i++){
		if (ans)return;
		tx = x+ turn[i][0];
		ty = y + turn[i][1];
		if (tx < 0 || ty < 0 || tx >= a || ty >= b)continue;
		if (vis[tx][ty] || mpt[tx][ty] == 'X')continue;
		vis[tx][ty] = 1;
		DFS(tx, ty, t - 1);
		vis[tx][ty] = 0;
	}
}
int main()
{
	while (cin >> a>>b>>time){
		if (!a&&!b&&!time)return 0;
		int i,j,si,sj,di=-1,dj=-1;
		ans = 0;
		memset(mpt, 0, sizeof(mpt));
		memset(vis, 0, sizeof(vis));
		for (i = 0; i < a; i++){ 
			cin >> mpt[i]; 
		}
		for (i = 0; i < a; i++)
		{
			for (j = 0; j < b; j++){
				if (mpt[i][j] == 'S'){
					si = i; sj = j;
					vis[si][sj] = 1;
				}
				else if (mpt[i][j] == 'D'){
					di = i; dj = j;
				}
			}
		}

				if (di == -1)ans = 0;//沒有門,剪枝
				else if ((si + sj + time) % 2 != (di + dj) % 2)ans = 0;//**奇偶性剪枝
				else DFS(si, sj, time);

				if (ans)cout << "YES" << endl;
				else cout << "NO" << endl;
	}
	return 0;
}



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