题目大意:一条狗因为一根骨头陷入了迷宫中,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; }