hdu 1010 Tempter of the Bone(dfs+奇偶剪枝)

版权声明:本文为博主原创文章,欢迎各位转载,但请带上本文地址。 https://blog.csdn.net/LD_1090815922/article/details/70665872

本题链接:点击打开链接

Tempter of the Bone

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


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
 

Recommend
JGShining   |   We have carefully selected several similar problems for you:   1242  1072  1026  1015  1253 
 
大致题意: 有一个陷阱迷宫,然后有一只狗被困在里面,迷宫大门在 T 时刻会开启(注意是时刻,也就是只在这一时刻门会打开),此时狗能逃出去。其中狗每走一块地板费时一秒,然后该地板在下一秒就会塌陷。现在从键盘输入 N ,M,T,N*M表示迷宫大小及地板数目,T代表过T秒后迷宫大门将开启,表示狗若刚好到达大门口就可以逃出去。问狗能不能逃出迷宫,可以就输出 YES,否则输出NO。

其中:

'X':表示墙,狗不能进入;
'S':表示狗的起始位置;
'D':表示大门;
'.'  :表示狗能走的路。

解题思路:一看题意就知道是一道搜索得题,果断用深搜,但很可惜,超时也很果断!然后网上查找了一些剪枝方法,慢慢的剪枝,总算剪枝到92MS AC。

剪枝方法1:如果可以走的地板数目小于给定的时间,那么绝对不可能得逃出。

剪枝方法2:还有就是狗走到门的时间必须和题目给定的时间是同奇同偶的,否则也不能在指定的那秒到达门,也不可能得逃出。

剪掉这两种情况后,就用深度搜索来做。从起点出发,深搜周围的路,走过的路就更新为墙,一直搜索下去,如果是一条“死路“”就回溯,把可能的路都搜索一遍过去,看看是否有“活路”。

这最用到最主要的剪枝方法就是奇偶剪枝,也简单介绍下:

可以把地图看成这样: 
0 1 0 1 0 1 
1 0 1 0 1 0 
0 1 0 1 0 1 
1 0 1 0 1 0 
0 1 0 1 0 1 
不难看出:

从任意 0 走到任意 1 或从任意1到任意0始终是奇数步;

从任意 0 走到任意 0 或从任意1到任意1始终是偶数步;

结论(对于此题):
所以当遇到从 0 走向 0 但是要求时间是奇数的,或者, 
从 1 走向 0 但是要求时间是偶数的 都可以直接判断不可能到达。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
char mp[10][10];
int n,m,t;
int dir[4][2]= {{0,1},{1,0},{-1,0},{0,-1}};
int sx,sy,ex,ey;            //sx,sy为起点 ex,ey为大门
bool flag;
void dfs(int x,int y,int tk)
{
    int nx,ny;
    if(flag)                //找到"活路"及时退出
        return;
    if(tk>t)
        return;
    if((t-tk-abs(x-ex)-abs(y-ey))%2==1)  //奇偶剪枝
        return;
    if(x==ex&&y==ey&&tk==t)             //找到活路
    {
        flag=true;
        return;
    }
    for(int i=0; i<4; i++)
    {
        nx=x+dir[i][0];
        ny=y+dir[i][1];
        if(mp[nx][ny]!='X'&&nx>=0&&ny>=0&&nx<n&&ny<m)
        {
            mp[nx][ny]='X';
            dfs(nx,ny,tk+1);
            mp[nx][ny]='.';       //回溯
            if(flag)             //找到"活路"及时退出
                return;
        }
    }
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&t)&&(n+m+t))
    {
        int w=0;
        memset(mp,'X',sizeof(mp));
        for(int i=0; i<n; i++)
            scanf("%s",mp[i]);
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
            {
                if(mp[i][j]=='S')
                {
                    
                    sx=i;
                    sy=j;
                    mp[sx][sy]='X';
                }
                if(mp[i][j]=='D')
                {
                    ex=i;
                    ey=j;
                }
                if(mp[i][j]=='X')
                    w++;        //统计墙的数量
            }
        if(n*m-w<t||(t-abs(sx-ex)-abs(sy-ey))%2==1||abs(sx-ex)+abs(sy-ey)>t)  //可走方块是否比时间少,最短时间是否比t大,奇偶剪枝
        {
            printf("NO\n");
            continue;
        }
       
        flag=false;
        dfs(sx,sy,0);
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/LD_1090815922/article/details/70665872