【HDU - 1010】Tempter of the Bone(dfs+剪枝)


Tempter of the Bone

直接上中文了

Descriptions:

暑假的時候,小明和朋友去迷宮中尋寶。然而,當他拿到寶貝時,迷宮開始劇烈震動,他感到地面正在下沉,他們意識到這是一個陷阱!他們想盡一切辦法逃出去。
迷宮是一個大小為 N*M 的長方形,迷宮中有一扇門。一開始,門是關着的,他會在第 t 秒的時間打開。因為,小明和朋友必須在第 t 秒到大門口。每一秒,他都可以向上下左右四個方向移動一個點。一旦他移動了,他剛才所在的點就消失,(這意味着他不能回到他已經走過的點)。他不能在一個點上停留超過一秒,並且不能走障礙點。小明和朋友能安全的逃出嗎?

Input

輸入由多個測試用例組成。每個測試用例的第一行包含三個整數 N、M 和 T ( 1 < N , M < 7 ; 0 < T < 50 ),分別表示迷宮的大小和門打開的時間。接下來的N行給出迷宮布局,每一行包含M個字符。下列字母分別表示:

"X": 一堵牆,小明和朋友不能在上面停留
"S": 起點
"D": 門
".": 可以走的點

輸入以 3 個 0 時結束。這個測試用例不需要處理。

Output

對於每組樣例輸出一行。
如果小明能夠安全逃出,輸出 "YES" ,否則輸出 "NO"。

Sample Input

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

Sample Output

NO
YES

題目鏈接:
https://vjudge.net/problem/HDU-1010

一開始沒讀清題 上去就bfs WA 了

然后想用bfs做,錯了好多次發現不行,bfs更加適用於求最短路徑等等最優化的題目由於這道題目時間給定,而到目的的所用卻不一定。即:可能有多種到達目的地的方法,不同方法需要的時間不同。並不要求是最短時間。所以bfs不合適

比如:

4 5 5
X X S . .
X X . . X
X . . . X
X . D . X
從S到D其實有很多條路的,最短3步,也可以有其他很多走法,不同走法需要的時間不同,用bfs求的是最短時間,如果題目時間是5呢?BFS答案是錯誤的,但是其實可以走到的。

然后dfs 結果超時 需要剪枝

奇偶剪枝:

是數據結構的搜索中,剪枝的一種特殊小技巧。
現假設起點為(sx,sy),終點為(ex,ey),給定t步恰好走到終點,
 
s        
|        
|        
|        
+ e
 
 
如圖所示(“|”豎走,“—”橫走,“+”轉彎),易證abs(ex-sx)+abs(ey-sy)為此問題類中任意情況下,起點到終點的最短步數,記做step,此處step1=8;
 
  
s  
  +  
| +      
|        
+ e
 
 
如圖,為一般情況下非最短路徑的任意走法舉例,step2=14;
step2-step1=6,偏移路徑為6,偶數(易證);
故,若t-[abs(ex-sx)+abs(ey-sy)]結果為非偶數(奇數),則無法在t步恰好到達;
返回,false;
反之亦反。
具體操作見代碼
AC代碼
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#define mod 1000000007
#define eps 1e-6
#define ll long long
#define INF 0x3f3f3f3f
#define MEM(x,y) memset(x,y,sizeof(x))
#define Maxn 10
using namespace std;
int T,n,m,steps;
int ex,ey,sx,sy;;
char mp[Maxn][Maxn];//原始地圖
int vis[Maxn][Maxn];//記錄人是否走過
int dt[][2]= {{1,0},{-1,0},{0,1},{0,-1}};//四個方向
int dfs(int x,int y,int step)//當前坐標 當前步數
{
    if(x==ex&&y==ey&&step==steps)//滿足條件,成功
        return 1;
    for(int i=0; i<4; i++)//四個方向
    {
        int tx=x+dt[i][0];
        int ty=y+dt[i][1];
        if(tx>=0&&tx<n&&ty>=0&&ty<m&&!vis[tx][ty]&&mp[tx][ty]!='X')//判斷條件
        {
            vis[tx][ty]=1;
            if(dfs(tx,ty,step+1))//繼續搜索
                return 1;
            vis[tx][ty]=0;//回溯
        }
    }
    return 0;
}
int main()
{
    while(cin>>n>>m>>steps,n+m+steps)
    {
        MEM(vis,0);//初始化
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
            {
                cin>>mp[i][j];
                if(mp[i][j]=='S')//起點
                {
                    sx=i,sy=j;
                    vis[sx][sy]=1;//標記
                }
                if(mp[i][j]=='D')//終點
                    ex=i,ey=j;
            }
        if((abs(ex-sx)+abs(ey-sy))%2!=steps%2)//剪枝,不然超時
            cout<<"NO"<<endl;
        else
        {
            if(dfs(sx,sy,0))
                cout<<"YES"<<endl;
            else
                cout<<"NO"<<endl;
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM