题目:HDU1010
Tempter of the Bone
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 161732 Accepted Submission(s): 42908
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
方法:
此题需要使用DFS和奇偶剪枝,否则会很容易超时。
剪枝部分:
int distance = abs(x-endx) + abs(y-endy);
if (distance % 2 != (T - t) % 2) //第一处,奇偶剪枝
return;
if (T - t < distance) //第二处,步数不够剪枝
return;
if (flag == true) //第三处,此前已经符合题意,故后续可以不做
break;
代码:(代码有两种写法,一种是使用辅助数组visit来帮助判断,另一种是直接在当前字符上进行修改)
法一,使用visit数组(推荐使用此法):
#include <bits/stdc++.h>
using namespace std;
int n, m, T;
int beginx, beginy, endx, endy;
char a[10][10];
bool visit[10][10];
bool flag;
int t;
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
void dfs(int x, int y)
{
if (a[x][y] == 'D') //到终点D
{
if (T == t) //符合题意,时间恰好为t时到达终点D
flag = true;
return; //到达D点,返回,时间可能正好为T,也可能不是
}
int distance = abs(x-endx) + abs(y-endy);
if (distance % 2 != (T - t) % 2) //奇偶剪枝
return;
if (T - t < distance) //步数不够剪枝
return;
for (int i = 0; i < 4; i++)
{
if (flag == true) //此前已经符合题意,故后续可以不做
break;
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if (tx > 0 && tx <= n && ty > 0 && ty <= m && a[tx][ty] != 'X' && visit[tx][ty] == false)
{ //先判断下一个位置的符合条件,再修改状态当前位置的状态
visit[x][y] = true;
t++;
dfs(tx, ty);
visit[x][y] = false; //回溯
t--;
}
}
}
int main()
{
while (cin >> n >> m >> T && n + m + T != 0)
{
memset(a, 0, sizeof(a)); //不要忘了初始化数组
memset(visit, false, sizeof(visit));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
cin >> a[i][j];
if (a[i][j] == 'S')
{
beginx = i;
beginy = j;
}
if (a[i][j] == 'D')
{
endx = i;
endy = j;
}
if (a[i][j] == 'X')
visit[i][j] = true;
}
t = 0;
flag = false;
dfs(beginx, beginy);
if (flag)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
法二,直接在a数组上修改字符:
#include <bits/stdc++.h>
using namespace std;
int n, m, T;
int beginx, beginy, endx, endy;
char a[10][10];
bool flag;
int t;
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
void dfs(int x, int y)
{
if (a[x][y] == 'D') //到终点D
{
if (T == t) //符合题意,时间恰好为t时到达终点D
flag = true;
return; //到达D点,返回,时间可能正好为T,也可能不是
}
int distance = abs(x-endx) + abs(y-endy);
if (distance % 2 != (T - t) % 2) //奇偶剪枝
return;
if (T - t < distance) //步数不够剪枝
return;
for (int i = 0; i < 4; i++)
{
if (flag == true) //此前已经符合题意,故后续可以不做
break;
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if (tx > 0 && tx <= n && ty > 0 && ty <= m && a[tx][ty] != 'X')
{ //先判断下一个位置的符合条件,再修改状态当前位置的状态
a[x][y] = 'X';
t++;
dfs(tx, ty);
a[x][y] = '.'; //回溯
t--;
}
}
}
int main()
{
while (cin >> n >> m >> T && n + m + T != 0)
{
memset(a, 0, sizeof(a)); //不要忘了每次前初始化数组
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
cin >> a[i][j];
if (a[i][j] == 'S')
{
beginx = i;
beginy = j;
}
if (a[i][j] == 'D')
{
endx = i;
endy = j;
}
}
t = 0;
flag = false;
dfs(beginx, beginy);
if (flag)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}