hdu 1010 Tempter of the Bone
这题是深搜的典型题,要在时间 t 内准确到达终点,处理不好要么 wa 要么 TLE。有两个很重要的剪枝:一是奇偶剪枝,必须提前判断好 'S'和'D' 之间的曼哈顿距离和时间 t 是否同奇偶,否则会 TLE;二是判断 '.' 的数量是否大于或等于 t-1,这个能使程序快很多,但不是必要的,我试了下把它去掉后还是能过,只是多了几倍的时间。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef const int& cintr; 6 int n,m,t,ei,ej; 7 8 inline int dist(cintr x, cintr y, cintr x2, cintr y2){ 9 return abs(x-x2)+abs(y-y2); 10 } 11 12 bool flag; 13 char map[10][10]; 14 int dir[2][4]= {{-1,0,0,1},{0,-1,1,0}}; 15 16 void dfs(int i, int j, int time){ 17 if(flag) return ; 18 if(i==ei && j==ej && time==t) { 19 flag= true; 20 return ; 21 } 22 int tmp= dist(i,j,ei,ej); 23 //不用再作奇偶剪枝的判断了,在主函数时已判断好,这里只需作时间的判断 24 if(time+tmp > t /*|| (tmp+t-time)&1*/) return ; 25 for(int k=0; k<4; ++k){ 26 cintr di= i+dir[0][k], dj= j+dir[1][k]; 27 char ch= map[di][dj]; 28 if(map[di][dj]!='X'){ 29 map[di][dj]= 'X'; 30 dfs(di,dj,time+1); 31 map[di][dj]= ch; 32 } 33 } 34 } 35 36 int main(){ 37 int i,j,si,sj; 38 while(~scanf("%d%d%d",&n,&m,&t),n){ 39 memset(map,'X',sizeof(map)); 40 flag= false; 41 int point= 0; 42 getchar(); 43 for(i=1; i<=n; ++i,getchar()) 44 for(j=1; j<=m; ++j) 45 if((map[i][j]= getchar())=='S') si= i, sj= j; 46 else if(map[i][j]=='D') ei= i, ej= j; 47 else if(map[i][j]=='.') ++point; 48 int tmp= dist(si,sj,ei,ej); 49 //两个很重要的剪枝,用point来作首要的判断(大大提高了效率), 50 //然后是奇偶剪枝,只需剪一次即可 51 if(point < t-1 || (tmp+t)&1) { 52 puts("NO"); 53 continue; 54 } 55 map[si][sj]= 'X'; 56 dfs(si,sj,0); 57 puts(flag? "YES":"NO"); 58 } 59 return 0; 60 }
后来想用 bfs 来做时发觉这题是不能用 bfs 的,因为 bfs 把后继结点都标记好后无法回退。