这里是题目链接
Tempter of the BoneTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 169633 Accepted Submission(s): 45019 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.
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:
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 |
先说一下题意,你落入了一个迷宫里,T秒后迷宫的大门会打开,你要从起点走到终点,还不能走重复的道路,并且要恰好在第T秒到达终点,才能出去,来到终点早了晚了都不行。给你地图的分布,问你能不能恰好走出这个迷宫。
这道题和以往的题不一样,以前是在时间限制内走到迷宫出口即可,现在是恰好在规定的时间到达,要求就有点苛刻
一开始也是用dfs跑的,但是会被TLE,就只能想法剪枝
首先想到的剪枝就是最短路径的剪枝 最短的路径当然是 没有任何障碍物的时候,横平竖直的走,即最短距离为
abs(ex-sx)+abs(ey-sy),如果这个距离小于T的话,那么很明显,你因为不能在规定时间内走到迷宫出口而挂掉
再一个就是 计算一下除去墙壁后迷宫可以走的面积的大小,如果小于T的话,肯定会因为时间剩余而无路可走,这里很坑的一点就是 m*n-wall<=T 这个等号是可以取到的,因为起点是不消耗时间的,在我的代码里这一个等号节省了234ms,还是比较可观的。
另一个剪枝打死也没想到啊,就是传说中的 奇偶剪枝,关于奇偶剪枝,有必要学习一下
自己比较鄙陋的见解 就是你剩余的时间和路径的最短距离的奇偶性是相同的。因为无论你怎么走,你把路径和最短的路径比较的话,它总是差了那么个偶数
sta | |||||
↓↓↓↑↓ | ↑ | → | ↓ | ||
↓↓↓↑↓ | ↑ | ↓ | |||
→→→ | →↑↑ | →→ | →↓→↓ | →→↑→ | end |
→ | ↑ |
如图所示,红色的是最短路径,黑色的是任意走的路径(你还可以再随机一点),我们把它将随机路径平移到和最短路径相同的道路上,我们就可以发现他一定会经过所有的最短路径,并且会比最短路径多出来偶数个长度,(个人理解是因为始终你都要经过最短路径,无论是上下左右,你都会走上去再拐回来,构成一个相互抵消的效果,不然就会偏离最短路径了),的确是不容易想到啊
剩余的就是dfs跑图代码了,至于为什么不用bfs,因为bfs往往找到的是耗时最少的路径,和我们的要求有点差距
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int mm = 9;
int book[mm][mm];
char mp[mm][mm];
int n, m, t;
int sx, sy, ex, ey;
int step = 0;
int wall = 0;
int to[4][2] = { 0,1,1,0,0,-1,-1,0 };
int flag = 0;
void dfs(int x, int y, int step) {
if (x == ex && y == ey && step == t) {
flag = 1;
return;
}
if (flag)
return;
int temp = t - step - (abs(x - ex) + abs(y - ey));//奇偶判重
if (temp < 0 || temp % 2 == 1)
return;
for (int i = 0; i < 4; i++) {
int nx = x + to[i][0];
int ny = y + to[i][1];
if (book[nx][ny] || nx < 0 || nx >= n || ny < 0 || ny >= m)
continue;
book[nx][ny] = 1;
dfs(nx, ny, step + 1);
book[nx][ny] = 0;
}
}
void init() {
step = 0;
wall = 0;
flag = 0;
for (int i = 0; i < mm; i++)
for (int j = 0; j < mm; j++)
book[i][j] = 0;
}
int main()
{
while (cin >> n >> m >> t) {
if (!n && !m && !t)break;
init();
for (int i = 0; i < n; i++) {
cin >> mp[i];
for (int j = 0; j < m; j++) {
if (mp[i][j] == 'S') {
sx = i;
sy = j;
}
if (mp[i][j] == 'D') {
ex = i;
ey = j;
}
if (mp[i][j] == 'X') {
book[i][j] = 1;
wall++;
}
}
}
if (n * m - wall <= t) {//空格数小于时间数
cout << "NO" << endl;
continue;
}
book[sx][sy] = 1;//!!!!!
dfs(sx, sy, 0);
if (flag)cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}