HDU1010迷宫问题

Tempter of the Bone

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

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
Author
ZHANG, Zheng
Source
ZJCPC2004
Recommend
JGShining

思路:
题目出的比较有感觉,简化一下题意就是,S是起点(start),D是目的点(Destination),X是不可达的点,寻找一条从S->D的路径,并且要求步数等于给点值T,一开始的想法是用BFS,例如Dijkstra求最短路径,但是发现,似乎有问题,因为这里并不要求的是路径最短,而是路径等于某一定值的情况,因此,可以考虑用回朔的方法,即DFS.一开始就直接用DFS的方法(非剪枝),
DFS(current status)
{
	Change status;
	visit(currentstatus);
	DFS(next status);
	Recovery status;
}
然后,成功地超时了,于是想到要剪枝,有哪些剪枝容易想到的呢?
1.如果能visit的所有格子总和<T,说明即使走完所有格子依然死路一条,需要剪枝!
2.visit的点坐标已经超过了map,需要剪枝!
3.抛开所有的障碍物,假设道路是畅通无阻的,我们最快也需要走的步数(从S->D)为dist=|si-di|+|sj-dj|,而当前还能走的时间为T-cnt,如果T-cnt < dist,说明不可达.需要剪枝!
还有什么可以剪枝呢?(这个我想不到了.)
4.奇偶性剪枝,即如果dist是奇数,则需要走奇数步才能到Destation,则当前剩余步数T-cnt为偶数,则不可能到达,需要剪枝!(奇偶性剪枝证明待续)
处理完上面的剪枝后,题目就变成一个经典的DFS了,目的达到.
#include <iostream> 
#include <string> 
#include <cstdlib> 
using namespace std;

char map[9][9]; 
int n,m,t,di,dj;// 终点坐标

bool escape; //标记是否逃离成功,1成功 0失败

int dir[4][2]={{0,-1},{0,1},{1,0},{-1,0}}; //4个方向

//(si,sj)表当前坐标,cnt当前已经走了cnt步
void DFS(int si,int sj,int cnt) 
{   
	int i,temp; 
	if(si>n||sj>m||si<=0||sj<=0) //坐标已经在map外,剪枝
		return; 
	if(cnt==t&&si==di&&sj==dj) //走了t步并且此时正在门口处,逃离成功!
		escape=1;
	if(escape) 
		return; 

	//t-cnt表示还剩下的时间,|si-di|+|sj-dj|表示走到终点所需的最快步数(假定中间无障碍物)
	//如果还剩余的时间<最快步数,则说明即使走的是最短路,花光了所有时间依然不可达
	//t-cnt与|si-di|+|sj-dj|不同奇同偶,则说明也不可达,判断是否同奇同偶可以相减取最低位
	//为0则同奇同偶
	temp=(t-cnt)-abs(si-di)-abs(sj-dj);
	if(temp<0||temp&1) 
		return; 
	for(i=0;i<4;i++)//下面就是典型的dfs思路
	{ 
		if(map[si+dir[i][0]][sj+dir[i][1]]!='X')
		{ 
			map[si+dir[i][0]][sj+dir[i][1]]='X'; //visit the state
			DFS(si+dir[i][0],sj+dir[i][1],cnt+1); 
			map[si+dir[i][0]][sj+dir[i][1]]='.'; //回朔,还原现场
		} 
	} 
	return; 
} 
int main() 
{ 
	int i,j,si,sj; 
	while(cin>>n>>m>>t)
	{ 
		if(n==0&&m==0&&t==0) break; 
		int wall=0;
		for(i=1;i<=n;i++) 
		{
			for(j=1;j<=m;j++)
			{ 
				cin>>map[i][j]; 
				if(map[i][j]=='S') { si=i; sj=j; } //start
				else if(map[i][j]=='D') { di=i; dj=j; } //destation
				else if(map[i][j]=='X') wall++; 
			} 
		}
		//可以走的格子比所需时间还短,说明即使走完了所有的格子依然死路一条
		if(n*m-wall<=t)
		{
			cout<<"NO"<<endl;
			continue;
		}
		escape=0; 
		map[si][sj]='X';
		DFS(si,sj,0); 
		if(escape)
			cout<<"YES"<<endl; 
		else 
			cout<<"NO"<<endl; 
	} 
	return 0; 
} 





你可能感兴趣的:(ACM)