試題請參見: http://acm.hdu.edu.cn/showproblem.php?pid=1010
題目概述
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.
解題思路
迷宮問題, 深度優先搜尋(回溯).
不過需要奇偶剪枝.
遇到的問題
一開始陷入了TLE, 之後又陷入了WA.
- 需要引入奇偶剪枝, 也就是說, 當剩餘步數( = 總步數 - 目前步數)為奇數時, 一定無法到達;
- 一開始是純暴力搜尋, 并沒有回溯. 引入了
數組之後成功解決;isVisited
- 一開始的思路是, 使用DFS計算出最小的步數, 然後再用奇偶剪枝, 但是事實證明, 這方法不可行(測試資料見下一節).
參考的測試資料
- http://acm.hdu.edu.cn/discuss/problem/post/reply.php?postid=7611&messageid=1&deep=0
- http://acm.hdu.edu.cn/discuss/problem/post/reply.php?postid=17995&messageid=1&deep=0
其中第2個資料就是為什麼計算最小步數是不可行的原因.
源代碼
#include <iostream>
#include <cmath>
const int MAX_SIZE = ;
bool isAccessible[MAX_SIZE][MAX_SIZE];
bool isVisited[MAX_SIZE][MAX_SIZE];
bool isExitReached = false;
void traverseMap(int currentX, int currentY, int exitX, int exitY, int currentSteps, int n, int m, int t) {
if ( currentX < || currentY < || currentX >= n || currentY >= m ) {
return;
}
if ( isExitReached ) {
return;
}
if ( currentSteps == t && currentX == exitX && currentY == exitY ) {
isExitReached = true;
return;
}
// Branch Cutting
int restSteps = t - currentSteps - std::abs(currentX - exitX) - std::abs(currentY - exitY);
if ( restSteps < || restSteps % != ) {
isExitReached = false;
return;
}
isVisited[currentX][currentY] = true;
if ( !isVisited[currentX][currentY - ] && isAccessible[currentX][currentY - ] ) {
traverseMap(currentX, currentY - , exitX, exitY, currentSteps + , n, m, t);
}
if ( !isVisited[currentX][currentY + ] && isAccessible[currentX][currentY + ] ) {
traverseMap(currentX, currentY + , exitX, exitY, currentSteps + , n, m, t);
}
if ( !isVisited[currentX - ][currentY] && isAccessible[currentX - ][currentY] ) {
traverseMap(currentX - , currentY, exitX, exitY, currentSteps + , n, m, t);
}
if ( !isVisited[currentX + ][currentY] && isAccessible[currentX + ][currentY] ) {
traverseMap(currentX + , currentY, exitX, exitY, currentSteps + , n, m, t);
}
isVisited[currentX][currentY] = false;
}
int main() {
int n = , m = , t = ;
while ( std::cin >> n >> m >> t ) {
if ( n == && m == && t == ) {
break;
}
isExitReached = false;
int startX = , startY = ;
int exitX = , exitY = ;
char mapPoint;
for ( int i = ; i < n; ++ i ) {
for ( int j = ; j < m; ++ j ) {
std::cin >> mapPoint;
if ( mapPoint == 'S' ) {
isAccessible[i][j] = true;
startX = i;
startY = j;
} else if ( mapPoint == 'D' ) {
isAccessible[i][j] = true;
exitX = i;
exitY = j;
} else if ( mapPoint == 'X' ) {
isAccessible[i][j] = false;
} else if ( mapPoint == '.' ) {
isAccessible[i][j] = true;
}
}
}
traverseMap(startX, startY, exitX, exitY, , n, m, t);
if ( isExitReached ) {
std::cout << "YES" << std::endl;
} else {
std::cout << "NO" << std::endl;
}
}
return ;
}