Tempter of the Bone 回溯法 还有奇偶剪枝

Tempter of the Bone

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


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

Sample Output
NO YES
 

Author
ZHANG, Zheng
 

Source
 

Recommend
JGShining   |   We have carefully selected several similar problems for you:  1016 1241 1072 1312 1026 
 


这道题啊,折磨了我好久,开始觉得,哦,BFS做就好了,但是范例能过,而实际上却不是合适办法,所以如果对于这道题还是有疑问的同学,只要看看这样一副图就好了。

2 4 7
S..D
....
所以最后参考大神们的代码,解决了本题中的关键问题。
这幅图的答案应该是yes,但是BFS的特点,就是只会保持同一层的而不能像DFS一样将整条路都递归出来,这样的好处是因为本题不能回头,所以每一条路的寻找都不能影响到其他的路径的寻找,每一次标记然后递归后要把标记去掉,所以这道题用回溯法。而且还有奇偶剪枝。

对于奇偶剪枝因为如果对于任何一个位置所在,还需要走的距离是奇数而剩下的时间是偶数,那么可以直接不考虑这条路了,主人公活不了的。直接return掉好了。

所以需要这样来避免时间上被卡住。

代码君

#include<cstdio>
#include<cmath>
#include<cstring>

using namespace std;
int   vid[9][9];
char  way[9][9];
int m,n,t;
bool flag = false;
struct Steps{
    int x,y;
};
Steps   walk,en;
const int mov[4][2] = {0,1,0,-1,1,0,-1,0};
void backtrack(int bx,int by,int ust){
    int need;
    if(flag)
        return;
    if(ust == t){
        if(bx == en.x && by == en.y){
            flag = true;
            return;
        }
    }
    need = fabs(bx - en.x)+fabs(by - en.y);
    int temp = t - ust - need;
    if(temp < 0||temp&1){
        return;
    }
    for(int i = 0;i < 4;i++){
        int tx,ty;
        tx = bx + mov[i][0];
        ty = by + mov[i][1];
        if(tx >= 0 && ty >= 0 && tx < n && ty < m && (way[ty][tx] == '.' || way[ty][tx] == 'D') && !vid[ty][tx]){
            vid[ty][tx] = 1;
            backtrack(tx,ty,ust+1);
            vid[ty][tx] = 0;
        }
    }
}
int main(){
    while(~scanf("%d %d %d",&m,&n,&t) && m){
        memset(way,'X',sizeof(way));
        flag = false;
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                scanf(" %c",&way[i][j]);
                if(way[i][j] == 'S'){
                    walk.x = j;
                    walk.y = i;
                }
                if(way[i][j] == 'D'){
                    en.x = j;
                    en.y = i;
                }
            }
        }
        memset(vid,0,sizeof(vid));
        vid[walk.y][walk.x] = 1;
        backtrack(walk.x,walk.y,0);
        if(flag)
            printf("YES
");
        else
            printf("NO
");
    }
    return  0;
}


原文地址:https://www.cnblogs.com/lccurious/p/5079879.html