Tempter of the Bone(DFS+剪枝)

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.

SampleInput

4 4 5
S.X.
..X.
..XD
....
3 4 5
S.X.
..X.
...D
0 0 0

SampleOutput

NO
YES

最開始看見這題直接看了樣例,以爲就是詢問t時間內能不能走出去,直接寫了個BFS過了樣例,提交上去WA了=7=,事實證明還是不能偷懶。
題意就是S當前位置,D是門,X是牆,問你能不能剛好在t時刻走到門D那裏。
然後就是套DFS,本地測試炸棧,就想到了剪枝一下
1 int tp = t - step - abs(dx - x) - abs(dy - y);
2 if(tp < 0 || tp % 2 == 1)
3     return ;

這就是剪枝代碼,dx和dy代表門的座標,x、y爲當前座標,step表示以及走了的步數。

當剩餘時間走不到門時結束,這個好理解,難理解的是爲什麼爲奇數是也結束。

因爲從s每走一步,一定是x或y進行+1或者-1,要使得t時間剛好走到門d。

最短路徑m = |dx - x| + |dy - y|;

兩種情況,t < m時,肯定無法到達;

t >= m時,從S到D的行走步驟兩部分組成,step = t = m + x;(m爲最段路徑,x爲附加步數);

這x = t - m步一定是從最短路徑中的某一步走出去,再回到最短路徑的步數,而且二者一定是相等的。

如圖,最短路徑爲橘色所示,附加路徑爲藍色所示,把藍色路徑分爲走出和走回兩部分,無論你怎麼添加附加路徑,這兩部分一定是相等的步數。

所以,x一定得爲偶數才能保證從S剛好走到D。

而在剪枝中,tp就是我們的x,只有當tp爲偶數時,才繼續行走。

完整代碼:

  1 #include <iostream>
  2 #include <string>
  3 #include <cstdio>
  4 #include <cstdlib>
  5 #include <sstream>
  6 #include <iomanip>
  7 #include <map>
  8 #include <stack>
  9 #include <deque>
 10 #include <queue>
 11 #include <vector>
 12 #include <set>
 13 #include <list>
 14 #include <cstring>
 15 #include <cctype>
 16 #include <algorithm>
 17 #include <iterator>
 18 #include <cmath>
 19 #include <bitset>
 20 #include <ctime>
 21 #include <fstream>
 22 #include <limits.h>
 23 #include <numeric>
 24 
 25 using namespace std;
 26 
 27 #define F first
 28 #define S second
 29 #define mian main
 30 #define ture true
 31 
 32 #define MAXN 1000000+5
 33 #define MOD 1000000007
 34 #define PI (acos(-1.0))
 35 #define EPS 1e-6
 36 #define MMT(s) memset(s, 0, sizeof s)
 37 typedef unsigned long long ull;
 38 typedef long long ll;
 39 typedef double db;
 40 typedef long double ldb;
 41 typedef stringstream sstm;
 42 const int INF = 0x3f3f3f3f;
 43 
 44 int n,m,t,flag,wall;
 45 int sx,sy,dx,dy;
 46 char mp[8][8];
 47 int vis[8][8];
 48 int fx[4][2] = {1,0,-1,0,0,1,0,-1};
 49 
 50 bool check(int x,int y){
 51     if(!vis[x][y] && mp[x][y] != 'X' && x >= 0 && y >= 0 && x < n && y < m){
 52         return true;
 53     }
 54     return false;
 55 }
 56 
 57 void dfs(int x,int y,int step){
 58     if(flag)
 59         return ;
 60     if(x == dx && y== dy && step == t){
 61         flag = 1;
 62         return ;
 63     }
 64 
 65     int tp = t - step - abs(dx - x) - abs(dy - y);
 66     if(tp < 0 || tp % 2 == 1)
 67         return ;
 68 
 69     for(int i = 0; i < 4; i++){
 70         int next_x = x + fx[i][0];
 71         int next_y = y + fx[i][1];
 72         if(check(next_x,next_y)){
 73             vis[next_x][next_y] = 1;
 74             dfs(next_x,next_y,step+1);
 75             if(flag)
 76                 return ;
 77             vis[next_x][next_y] = 0;
 78         }
 79     }
 80     return ;
 81 }
 82 
 83 int main(){
 84     ios_base::sync_with_stdio(false);
 85     cout.tie(0);
 86     cin.tie(0);
 87     while(cin>>n>>m>>t && n && m && t){
 88         fill(vis[0],vis[0]+64,0);
 89         MMT(mp);
 90         flag = 0, wall = 0;
 91         for(int i = 0; i < n; i++)
 92             cin>>mp[i];
 93         for(int i = 0; i < n; i++){
 94             for(int j = 0; j < m; j++){
 95                 if(mp[i][j] == 'S')
 96                     sx = i,sy = j;
 97                 if(mp[i][j] == 'D')
 98                     dx = i,dy = j;
 99                 if(mp[i][j] == 'X')
100                     wall++;
101             }
102         }
103         if(t < abs(dx - sx) + abs(dy - sy) || t > n*m - wall - 1){
104             cout << "NO" << endl;
105             continue;
106         }
107         vis[sx][sy] = 1;
108         dfs(sx,sy,0);
109         if(flag)
110             cout << "YES" << endl;
111         else
112             cout << "NO" << endl;
113     }
114 
115     return 0;
116 }