HDU1010 Tempter of the Bone(DFS+奇偶剪枝)

題目:HDU1010

 

Tempter of the Bone

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

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

 

方法:

此題需要使用DFS和奇偶剪枝,否則會很容易超時。

此處只看鏈接中的剪枝條件介紹

DFS奇偶性剪枝(HDU1010爲例)

剪枝部分:

int distance = abs(x-endx) + abs(y-endy);
if (distance % 2 != (T - t) % 2)	//第一處,奇偶剪枝 
	return;

if (T - t < distance)                   //第二處,步數不夠剪枝
	return;

if (flag == true)			//第三處,此前已經符合題意,故後續可以不做 
	break;

代碼:(代碼有兩種寫法,一種是使用輔助數組visit來幫助判斷,另一種是直接在當前字符上進行修改)

法一,使用visit數組(推薦使用此法):

#include <bits/stdc++.h>
using namespace std;
int n, m, T;
int beginx, beginy, endx, endy;
char a[10][10];
bool visit[10][10];
bool flag;
int t;
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

void dfs(int x, int y)
{
	if (a[x][y] == 'D')			//到終點D 
	{
		if (T == t)		        //符合題意,時間恰好爲t時到達終點D 
			flag = true;
		return;				//到達D點,返回,時間可能正好爲T,也可能不是 
	}
	int distance = abs(x-endx) + abs(y-endy);
	if (distance % 2 != (T - t) % 2)	//奇偶剪枝 
		return;
	if (T - t < distance)			//步數不夠剪枝
		return;
	for (int i = 0; i < 4; i++)
	{
		if (flag == true)		//此前已經符合題意,故後續可以不做 
			break;
		int tx = x + dir[i][0];
		int ty = y + dir[i][1];
		if (tx > 0 && tx <= n && ty > 0 && ty <= m && a[tx][ty] != 'X' && visit[tx][ty] == false)
		{				//先判斷下一個位置的符合條件,再修改狀態當前位置的狀態 
			visit[x][y] = true;
			t++;
			dfs(tx, ty);
			visit[x][y] = false;	//回溯 
			t--;
		}
	}
}

int main()
{
	while (cin >> n >> m >> T && n + m + T != 0)
	{
		memset(a, 0, sizeof(a));        //不要忘了初始化數組
		memset(visit, false, sizeof(visit));
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
			{
				cin >> a[i][j];
				if (a[i][j] == 'S')
				{
					beginx = i;
					beginy = j;
				}
				if (a[i][j] == 'D')
				{
					endx = i;
					endy = j;
				}
				if (a[i][j] == 'X')
					visit[i][j] = true;
			}
		
		t = 0;
		flag = false;
		dfs(beginx, beginy);
		if (flag)
			cout << "YES" << endl;
		else
			cout << "NO" << endl;
	}
	
	return 0;
}

法二,直接在a數組上修改字符:

#include <bits/stdc++.h>
using namespace std;
int n, m, T;
int beginx, beginy, endx, endy;
char a[10][10];
bool flag;
int t;
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

void dfs(int x, int y)
{
	if (a[x][y] == 'D')			//到終點D 
	{
		if (T == t)			//符合題意,時間恰好爲t時到達終點D 
			flag = true;
		return;				//到達D點,返回,時間可能正好爲T,也可能不是 
	}
	int distance = abs(x-endx) + abs(y-endy);
	if (distance % 2 != (T - t) % 2)	//奇偶剪枝 
		return;
	if (T - t < distance)			//步數不夠剪枝
		return;
	for (int i = 0; i < 4; i++)
	{
		if (flag == true)		//此前已經符合題意,故後續可以不做 
			break;
		int tx = x + dir[i][0];
		int ty = y + dir[i][1];
		if (tx > 0 && tx <= n && ty > 0 && ty <= m && a[tx][ty] != 'X')
		{				//先判斷下一個位置的符合條件,再修改狀態當前位置的狀態 
			a[x][y] = 'X';
			t++;
			dfs(tx, ty);
			a[x][y] = '.';		//回溯 
			t--;
		}
	}
}

int main()
{
	while (cin >> n >> m >> T && n + m + T != 0)
	{
		memset(a, 0, sizeof(a));        //不要忘了每次前初始化數組
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
			{
				cin >> a[i][j];
				if (a[i][j] == 'S')
				{
					beginx = i;
					beginy = j;
				}
				if (a[i][j] == 'D')
				{
					endx = i;
					endy = j;
				}
			}
		
		t = 0;
		flag = false;
		dfs(beginx, beginy);
		if (flag)
			cout << "YES" << endl;
		else
			cout << "NO" << endl;
	}
	
	return 0;
}

 

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