hdu 1011 Tempter of the Bone【DFS+奇偶性剪枝】

来源:互联网 发布:学生党淘宝店铺白菜价 编辑:程序博客网 时间:2024/06/04 20:03

Tempter of the Bone

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


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
 
直接DFS+剪枝没有过、在网上学到了一个叫做奇偶性剪枝的技巧,get√    
假如我们有一个4*4的图: 

. . . .. . . .. . . .. . . .
现在假如我们起点是(1,1),走向各个点的时间消耗为:

0 1 2 31 2 3 42 3 4 53 4 5 6
我们再使得他们的时间消耗进行奇偶数判断:(0表示偶数,1表示奇数):

0 1 0 11 0 1 00 1 0 11 0 1 0
设起点为(x,y),目标点为(ex,ey);

我们看的出来,从0--------0需要偶数步,从0--------------1需要奇数步、

如果abs(x-y)+abs(dx-dy)为偶数,则说明 abs(x-y) 和 abs(dx-dy)的奇偶性相同,需要走偶数步、(1)

如果abs(x-y)+abs(dx-dy)为奇数,则说明 abs(x-y) 和 abs(dx-dy)的奇偶性不同,需要走奇数步、(2)

如果我们知道了(从这个题目出发的结论)剩余步数,当前坐标和目标坐标。我们能够由(1)和(2)来判断从当前坐标到目标坐标的奇偶性x,这个时候不难理解,当前坐标到目标坐标的奇偶性和剩余步数的奇偶性一定要相同才有可能走到目标坐标。

AC代码:

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>using namespace std;char a[10][10];int vis[10][10];int fx[4]={1,-1,0,0};int fy[4]={0,0,1,-1};int x,y,step;int flag;int n,m;int ex,ey;void dfs(int x,int y,int cur){    int tmp=step-cur-abs(x-ex)-abs(y-ey);//重要剪枝、奇偶性剪枝、    if(tmp<0||tmp%2==1)    {        return ;    }    if(flag==1)//简单剪枝1、如果找到了可行方案,回溯即可    {        return ;    }    if(cur==step)    {        if(x==ex&&y==ey)        {            flag=1;            //return ;        }        return ;    }    for(int i=0;i<4;i++)    {        int xx=x+fx[i];        int yy=y+fy[i];        if(xx>=0&&xx<n&&yy>=0&&yy<m&&vis[xx][yy]==0&&a[xx][yy]=='.'||a[xx][yy]=='D')//这里有坑,写成!='X'是会wa的,测试数据有坑....        {            vis[xx][yy]=1;            dfs(xx,yy,cur+1);            if(flag==1)return ;            vis[xx][yy]=0;        }        if(flag==1)return ;//简单剪枝2    }}int main(){    while(~scanf("%d%d%d",&n,&m,&step))    {        if(n==0&&m==0&&step==0)break;        int x,y;        for(int i=0;i<n;i++)        {            scanf("%s",a[i]);            for(int j=0;j<m;j++)            {                if(a[i][j]=='S')                {                    x=i;                    y=j;                }                if(a[i][j]=='D')                {                    ex=i;                    ey=j;                }            }        }        flag=0;        memset(vis,0,sizeof(vis));        dfs(x,y,0);        if(flag==1)        {            printf("YES\n");        }        else        {            printf("NO\n");        }    }}







1 0