寒假前刷题(7)搜索系列 dfs hdu 1010

来源:互联网 发布:数据精灵破解版 编辑:程序博客网 时间:2024/06/07 06:26

Tempter of the Bone

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


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 5S.X...X...XD....3 4 5S.X...X....D0 0 0
 

Sample Output
NOYES
 


这是我做的第一道dfs的搜索题,看了非常长的时间,最后还是的借鉴别人的想法,不过我第一次接触到了关于剪枝的相关的问题。这倒题如果什么都不做,直接就dfs的话,那么结果只有超时,这里我学到了一个方法就是奇偶剪枝,所谓奇偶剪枝可以用下面的这个矩阵来说明:

  1. 0 1 0 1 0 1
  2. 1 0 1 0 1 0
  3. 0 1 0 1 0 1
  4. 1 0 1 0 1 0
  5. 0 1 0 1 0 1 

我们可以看到如果,0想到达另一个0必须走偶数步,而要走到1需要的是奇数步。所以如果要是要走到0时间确实是奇数的可以直接忽略,反之亦然。

这就是奇偶剪枝。

关键上就是在比较abs(endx-startx)+abs(endy-starty)的奇偶性。

下面是代码:


 

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>

using namespace std;

int t,ex,ey,n,m,step;
bool flag;
char map[10][10];
int  dir[4][2]={0,1,1,0,0,-1,-1,0}; //这个是遍历数组,我是按的顺时针方向,这个题按逆时针方向会超时,所以遍历数组以后再用的时候要学会灵活的变换

void dfs(int i,int j,int step)
{
     if(i==ex&&j==ey&&step==t)
        flag=true;
     if(step>t)
       return;
     if(flag)
       return;
     if((t-step)%2!=(abs(ex-i)+abs(ey-j))%2)//判断剩余时间与步数中间的奇偶性
        return;
     for(int u=0;u<4;u++)
     {
          int x=i+dir[u][0];
          int y=j+dir[u][1];
        if(x>=0&&x<n&&y>=0&&y<m)
        {
            if(map[x][y]!='X')
            {
              map[x][y]='X';
              dfs(x,y,step+1);;
              map[x][y]='.';  //回溯法,在回去的时候要恢复,这样才能够遍历搜索下去。
            }
        }
     }
}

int main()
{
     while(cin>>n>>m>>t)
     {
          if(n==0&&m==0&&t==0)
             break;
             int i,j,k=0;
             int x,y;
          for(i=0;i<n;i++)
            for(j=0;j<m;j++)
             {
                  cin>>map[i][j];
                  if(map[i][j]=='S')
                  {
                       x=i;
                       y=j;
                       map[x][y]='X';
                  }
                  if(map[i][j]=='D')
                  {
                       ex=i;
                       ey=j;
                       k++;
                  }
                  if(map[i][j]=='.')
                       k++;
             }
          if(k<t)  //这里我第一次忘记写了,后来看了参考才想起来,这不是求最短路径,要求的是刚好那个点到哪里,所以必须刚好是t

        {
            cout<<"NO"<<endl;
            continue;
          }
            flag=false;
            dfs(x,y,0);
            if(flag)
              cout<<"YES"<<endl;
            else
              cout<<"NO"<<endl;
     }
     return 0;
}