Temple of the bone - 九度 OJ 1461

Temple of the bone - 九度 OJ 1461

題目

時間限制:1 秒 內存限制:32 兆 特殊判題:否
題目描述:
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.
輸入:
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.
輸出:
For each test case, print in one line “YES” if the doggie can survive, or “NO” otherwise.
樣例輸入:
4 4 5
S.X.
…X.
…XD

3 4 5
S.X.
…X.
…D
0 0 0
樣例輸出:
NO
YES

題目大意:有一個 N*M 的迷宮,包括起點 S,終點 D,牆 X,和地面,0秒時主人公從 S 出發,每秒能走到四個與其相鄰的位置中的一個,且每個位置被行走之後都不能再次走入,問是否存在這樣一條路徑使主人公在 T 秒時剛好走到 D。

在這個問題中,題面不再要求我們求解最優解,而是轉而需要我們判定是否存在一條符合條件的路徑,所以使用深度優先搜索來達到這個目的。確定狀態三元組(x,y,t),(x,y)爲當前點座標,t 爲從起點走到該點所需的時間。我們需要的目標狀態爲(dx,dy,T),其中(dx,dy)爲 D 所在點的座標,T 爲所需的時間。初始狀態爲(sx,sy,0),其中(sx,sy)爲 S 所在點的座標。

同樣的,在深度優先搜索中也需要剪枝,我們同樣不去理睬被判定不可能存在所需狀態的子樹,以期能夠減少所需遍歷的狀態個數,避免不必要的超時。這裏注意到,主人公每走一步時,其所在位置座標中,只有一個座標分量發生增一或者減一的改變,那麼兩個座標分量和的奇偶性將發生變化。這樣,當主人公走過奇數步時,其所在位置座標和的奇偶性必與原始位置不同;而走過偶數步時,其座標和的奇偶性與起點保持不變。若起點的座標和的奇偶性和終點的座標和不同,但是需要經過偶數秒使其剛好達到,顯然的這是不可能的,於是我們直接判定這種情況下,整棵解答樹中都不可能存在我們所需的狀態,跳過搜索部分,直接輸出 NO。

#include <stdio.h>

char maze[8][8];//保存地圖信息
int n,m,t;//地圖大小爲n*m,從起點到終點能否恰好t秒
bool success;//能否找到所需狀態標記
int go[][2]={
    1,0,
    -1,0,
    0,1,
    0,-1
};//四個方向行走座標差

void DFS(int x,int y,int time){
    //遞歸形式的深度優先搜索
    for(int i=0;i<4;i++){
        //枚舉四個相鄰位置
        int nx=x+go[i][0];
        int ny=y+go[i][1];//計算其座標
        if(nx<1 || nx>n || ny<1 || ny>m)continue;
        //若座標在地圖外則跳過

        if(maze[nx][ny]=='X')continue;//若該位置爲牆,跳過
        if(maze[nx][ny]=='D'){
            //若該位置爲門
            if(time+1 == t){
                //若所用時間恰好爲t
                success=true;//搜索成功
                return;//返回
            }
            else continue;
            //否則該狀態的後續狀態不可能爲答案
            //(經過的點不能再經過),跳過
        }
        maze[nx][ny]='X';
        //該狀態擴展而來的後續狀態中,該位置都不能被經過,
        //直接修改該位置爲牆

        DFS(nx,ny,time+1);//遞歸擴展該狀態,所用時間遞增
        maze[nx][ny]='.';
        //若後續狀態全部遍歷完畢,則退回上層狀態,
        //將因爲要搜索其後續狀態而改成牆的位置,改回普通位置

        if(success)return;//假如已經成功,則直接返回,停止搜索
    }
}

int main()
{
    while(scanf("%d%d%d",&n,&m,&t)!=EOF){
        if(n==0 && m==0 && t==0)break;

        for(int i=1;i<=n;i++){
            scanf("%s",maze[i]+1);
        }

        success=false;//初始化成功標記
        int sx,sy;
        for(int i=1;i<=n;i++){
            //尋找D的位置座標
            for(int j=1;j<=m;j++){
                if(maze[i][j]=='D'){
                    sx=i;
                    sy=j;
                }
            }
        }

        for(int i=1;i<=n;i++){
            //尋找初始狀態
            for(int j=1;j<=m;j++){
                if(maze[i][j]=='S' && (i+j)%2==((sx+sy)%2+t%2)%2){
                    //找到S點後,先判斷S與D的奇偶性關係,
                    //是否和t符合,即符合上式,若不符合直接跳過搜索
                    maze[i][j]='X';//將起點標記爲牆
                    DFS(i,j,0);//遞歸擴展初始狀態
                }
            }
        }
        puts(success==true ? "YES" : "NO");
        //若success爲真,則輸出yes
    }
    return 0;
}

如該代碼所示,我們用遞歸函數完成深度優先搜索。深度優先搜索的各要素如下:
搜索空間:廣度優先搜索相同,依舊是所有的狀態。
搜索目的:查找一個可以表示原問題解的狀態。
搜索方法:在解答樹上進行先序遍歷。

總結深度優先搜索的相關特點:
其查找空間和查找目的均與廣度優先搜索保持一致,與廣度優先搜索有較大不同的是它的查找方式。深度優先搜索對狀態的查找採用了立即擴展新得到的狀態的方法,我們常使用遞歸函數來完成這一功能。正是由於採用這樣的擴展方法,由它搜索而來的解不再擁有最優解的特性,所以我們常用它來判斷解是否存在的存在性判定。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章