HDU1010 Tempter of the Bone DFS+剪枝

题目大意:一条狗因为一根骨头陷入了迷宫中,time=0时刻狗在迷宫的入口S处,狗每一次只能移动到上,下,左,右中临近的有效格中(即题目中的 " . ")且只能呆1秒的时间(真是太为难这只可怜的doggie了),走过的路在下一秒塌陷(即不能重复走路),问你这条狗能否在第T秒(time=T时)恰好走到迷宫的出口D处。

很显然这道题是搜索题,但提交时就会发现问题来了,直接DFS果断TLE了。

其实这道题考察的是剪枝,对于剪枝,搜索中常用的剪枝有:奇偶剪枝和路径剪枝。

所谓奇偶剪枝:

我们把一个矩阵标记成如下01形式:

0 1 0 1 0

1 0 1 0 1

0 1 0 1 0

1 0 1 0 1

很明显,如果起点在0,终点在1,那么需要经过奇数步才能走到,起点在0,终点也在0时需要经过偶数步才能走到,

简单的记就是:奇偶相同偶数步,奇偶不同奇数步。

这步剪枝在读入数据的时候就可以判断,当然没必要把,整个图都用0,1刷一遍,读入的时候可以把起点记为(sx,sy),终点记为(dx,dy),直接判断(sx+sy)和(dx和dy)的奇偶性就可以了。

所谓路径剪枝:

矩阵的大小是n*m的,墙的数量即为w,如果能走的道路的数量n*m-w小于时间T,那么无论如何这条狗也走不出去,这种情况就可以提前跳出去了。

有了这两层剪枝,时间就大大缩短下来了。

具体代码如下:

#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;
int dir[4][2]={{0,-1},{0,1},{1,0},{-1,0}};
char map[10][10];
int sx,sy,dx,dy;
int n,m,t;
bool flag;
void dfs(int x,int y,int cnt)
{
    if(x>n||y>m||x<=0||y<=0) return ;
    if(x==dx&&y==dy&&cnt==t)
    {
        flag=true;
        return ;
    }
    int tmp=(t-cnt)-abs(x-dx)-abs(y-dy);
    if(tmp<0||tmp%2==1) return ;
    for(int i=0;i<4;i++)
      if(map[x+dir[i][0]][y+dir[i][1]]!='X')
      {
          map[x+dir[i][0]][y+dir[i][1]]='X';
          dfs(x+dir[i][0],y+dir[i][1],cnt+1);
          if(flag) return ;
          map[x+dir[i][0]][y+dir[i][1]]='.';
      }
}
int main()
{
    int i,j;
    while(scanf("%d%d%d",&n,&m,&t))
    {
        if(n==0&&m==0&&t==0) break;
        int w=0;
        for(i=1;i<=n;i++)
          for(j=1;j<=m;j++)
          {
              cin>>map[i][j];
              if(map[i][j]=='X') w++;
              if(map[i][j]=='S') { sx=i;sy=j; }
              if(map[i][j]=='D') { dx=i;dy=j; }
          }
        if(n*m-w<=t) puts("NO");
        else
        {
            flag=false;
            map[sx][sy]='X';
            dfs(sx,sy,0);
            if(flag) puts("YES");
            else puts("NO");
        }
    }
    return 0;
}



你可能感兴趣的:(HDU1010 Tempter of the Bone DFS+剪枝)