HDU 1010 Temper of the Bone
阿新 • • 發佈:2018-11-01
一、題目描述
幫助doggie走出迷宮。迷宮由‘S’(起點)、‘X’(牆,不可通過)、‘D’(終點)、和‘.’(可走格子)組成。給定時間T,doggie每秒走一格,要求不可重複走,且剛好在T秒內走到終點D。如果有這樣的路徑,輸出“YES”,否則“NO”。
二、樣例
輸入:
4 4 5 S.X. ..X. ..XD .... 3 4 5 S.X. ..X. ...D 0 0 0 輸出:NO YES
三、分析
深搜DFS問題。從起點開始,doggie每秒有4種走法,即上、下、左、右,下一秒又在上一次的基礎上有4種選擇。我們要做的就是對這所有的情況剪枝。
1、邊界。遇到迷宮的邊緣,或者代表無法通過的X,不再繼續搜尋;
2、重複。已經走過的區域不再重複搜尋;
3、奇偶剪枝。這個不太容易想到。可以這樣考慮:先計算起點到終點的最短距離d,由於有牆的存在,給的時間走過的步數T減去最短距離d,也就是需要繞路走的步數 t = T - d。這個繞路步數必須是偶數,否則無法到達終點。
4、時間。如果給的時間超過可走的步數+1,則一定無法到達。具體可以看這個樣例:
2 4 7 S..D ....
可走塊數sum為6,時間T為7,剛好走完所有塊到達終點。若sum < T - 1,一定無法到達。
另外要注意的就是遞迴,要小心跳出條件和恢復上一層。
四、程式碼
/********************************************** *時間:2018-01-29 *內容:深搜+剪枝 *技巧:搜尋的時候剪枝一定要考慮完全,能剪的都 剪掉,否則容易超時;遞迴思路要清晰 ***********************************************/ #include<iostream> #include<cstring> #include<cmath> #include <stdlib.h> using namespace std; int dx[4]={1,0,-1,0},dy[4]={0,-1,0,1}; int n,m,t,sum; //記錄迷宮大小和時間,可走的塊數 int sx,sy,ex,ey; //記錄起點和終點座標 char maze[7][7]; bool record[7][7];//記錄迷宮是否被走過 bool flag = false; void dfsMaze(int nx,int ny,int layer) { if(layer == t ){ //跳出條件 if(maze[nx][ny] == 'D' ) flag = true; return; } for(int i = 0; i < 4; ++ i){ //排除邊界情況 if(nx + dx[i] < 0 || nx + dx[i] == n || ny + dy[i] < 0 || ny + dy[i] == m) continue; //對牆 和 已經走過的部分 剪枝 if(maze[nx + dx[i]][ny + dy[i]] == 'X' || !record[nx + dx[i]][ny + dy[i]]) continue; //如果在時間到之前就走到D,也無法走出迷宮。剪枝 if(layer < t - 1 && maze[nx + dx[i]][ny + dy[i]] == 'D') continue; record[nx+dx[i]][ny+dy[i]] = false; //記錄該塊已經走過 nx = nx + dx[i]; ny = ny + dy[i]; //進入下一層搜尋 dfsMaze(nx,ny,++ layer); //恢復 if(flag) return; //只要找到一條路線,就不再尋找 record[nx][ny] = true; layer --; nx = nx - dx[i]; ny = ny - dy[i]; } } int main() { while(true){//讀入資料 cin>>n>>m>>t; if(n==0) break; memset(record,true,sizeof(record)); flag = false; sum = 0; for(int i = 0;i < n; ++ i){ for(int j = 0;j < m; ++ j){ cin >> maze[i][j]; if(maze[i][j] == '.') sum++; //記錄終點和起點位置 if(maze[i][j] == 'D'){ex = i;ey = j;} if(maze[i][j] == 'S'){sx = i;sy = j;record[i][j] = false;} } } //如果可走的步數小於時間-1,或者需要繞彎走的步數是奇數,不可到達 if(sum < t - 1 || (t - (abs(sx - ex) + abs(sy - ey))) % 2)cout<< "NO" <<endl; else{ dfsMaze(sx,sy,0); if(flag) cout << "YES" << endl; else cout << "NO" << endl; } } }