现在的位置: 首页 > 综合 > 正文

ZOJ 2110 ( HDU 1010 ) Tempter of the Bone( 比较经典的DFS) –from lanshui_Yang

2019年01月08日 ⁄ 综合 ⁄ 共 3253字 ⁄ 字号 评论关闭

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

          题目大意:一只小狗在一个古老的迷宫里找到一根骨头,当它叼起骨头时,迷宫开始颤抖,它感觉到地面开始下沉。它才明白骨头是一个陷阱,它拼命地试着逃出迷宫。
          迷宫是一个N×M 大小的长方形,迷宫有一个门。刚开始门是关着的,并且这个门会在第T 秒 钟开启,门只会开启很短的时间(少于一秒),因此小狗必须恰好在第T 秒达到门的位置。每秒钟, 它可以向上、下、左或右移动一步到相邻的方格中。但一旦它移动到相邻的方格,这个方格开始下沉,而且会在下一秒消失。所以,它不能在一个方格中停留超过一秒,也不能回到经过的方格。

          判断小狗是否能成功逃离。

       输入描述:

       输入文件包括多个测试数据。每个测试数据的第一行为三个整数:N M T,(1<N, M<7;0<T<50),分别代表迷宫的长和宽,以及迷宫的门会在第T 秒时刻开启。接下来N 行信息给出了迷宫的格局,每行有M 个字符,这些字符可能为如下值之一:

            X: 墙壁,小狗不能进入                   S: 小狗所处的位置
D: 迷宫的门                                        . : 空的方格
       输入数据以三个0 表示输入数据结束。
       对每个测试数据,如果小狗能成功逃离,则输出"YES",否则输出"NO"。

       


       笔者感受:此题是一道比较经典的DFS题,关键在于 每次访问完一点后 ,要把此点的状态 复原 ,并且 此题 需要运用 剪枝法,而且 需要多处剪枝,否则 很容易TLE !!(朋友们 是不是 也有同感啊 ~)

  具体讲解请看代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int n,m,t;
int X[4]= {-1,1,0,0};   // 定义前进方向
int Y[4]= {0,0,-1,1};
char map[9][9];
void dfs(int si,int sj);
int cango(int i ,int j);
int cnt ;              // 记录步数
bool f ;
int di,dj;            //  目的地 坐标
int main()
{
    while (scanf("%d%d%d",&n,&m,&t)!=EOF)
    {
        if(n==0 && m==0 && t==0)
            break;
        int i,j;
        cnt = 0;
        f = false;  // 先把 f 的值赋为 false
        int wall = 0;  // 记录 ‘X’的数目 ,用于 以后的 剪枝
        int si ,sj;
        char t1;
        t1 = getchar();  // 注意 : 此处 是为了 吃掉 输入 n,m,t 后的 换行符  !!
        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;
                }
                if(map[i][j] == 'D')
                {
                    di = i;
                    dj = j;
                }
                if(map[i][j] == 'X')
                    wall++;
            }
            t1 = getchar();   // 此处 也是为了吃掉 每行 末尾的 换行符 !!
        }
        if(n*m - wall <= t)  // 此处 为剪枝 ,道理 比较容易想
        {
            printf("NO\n");
            continue;
        }
        else
        {
            dfs(si,sj);
            if(f == true)
                printf("YES\n");
            else
                printf("NO\n");
        }
    }
    return 0;
}

void dfs(int si,int sj)   // 深搜
{
    int temp;
    if( si>n || sj>m || si<=0 || sj<=0 ) return;  // 判断边界
    if(si == di && sj == dj && cnt == t)
    {
        f = true;
        return ;
    }
    temp = (t-cnt) - abs(si-di) - abs(sj-dj);  // 注意 : 此处 为剪枝(此题中最重要的剪枝,如果没有,会果断TLE) ,此处 较难 理解,                                                                     //  请亲自 动手模拟
    if( temp<0 || temp%2 ) return;           //  如果 temp 小于0 或者 是奇数 ,那么 小狗 就不能 到达目的地
    map[si][sj]='X';                        // 把访问的点标记为‘X’
    int k;
    for (k = 0; k<4; k++)
    {
        if(cango(si+X[k],sj+Y[k]))
        {
            cnt ++;
            dfs(si+X[k],sj+Y[k]);
            if(f)              // 注意 : 此处 也为剪枝 (比较重要,如果没有 ,也会果断TLE)
                return ;
            cnt --;
        }
    }
    map[si][sj]='.';   // 注意: 此处即为 状态复原 !!(很关键)
    return ;
}

int cango(int i ,int j)   // 判断此点能否被访问
{
    if(map[i][j]!='X'&&cnt<=t)
        return 1;
    return 0;
}

抱歉!评论已关闭.