原题地址
http://ac.jobdu.com/problem.php?pid=1456
给定一个三维迷宫,求从入口到出口的最短路径。
解题思路
本题的题意很容易懂,因为刚刚写了几道DFS,所以很自然就用DFS去做这道题,可是不管怎么剪枝都1000ms+超时,改用BFS马上就用30ms AC了,可见两者在耗时上的差别实在是大。
详见大神总结的[BFS和DFS区别](http://blog.csdn.net/u013551536/article/details/50926922)
BFS是按一层一层来访问的,优先访问的是兄弟节点,只有这一层全部访问完才能访问下一层,也就是说BFS第几层就代表以当前代价可以走到的位置(结点),适合用来搜索最短路径长度、最少费用问题!
DFS是按递归来实现的,它优先搜索深度,再回溯,优先访问的是没有访问过的子节点,求得的路径可能不是最短路径(但是可以打印路径),适合用来搜索能否到达目的地、连通性问题!
用三维数组模拟迷宫,用二维数组表示每个点相邻的六个方向(上下左右前后),然后用队列模拟BFS的过程,实现思路比较清晰。
AC代码
成功的BFS:
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
typedef struct node
{
int x, y, z;
int step;
node(int x1, int y1, int z1, int step1) //初始化赋值
{
x = x1, y = y1, z = z1;
step = step1;
}
}NODE;
const int maxn = 55;
int puzzle[maxn][maxn][maxn];
bool visited[maxn][maxn][maxn]; //标记某个点是否被访问过
int A, B, C, limit;
int dir[6][3] =
{
-1, 0, 0, //up
1, 0, 0, //down
0, 0, -1, //left
0, 0, 1, //right
0, -1, 0, //back
0, 1, 0 //front
};
int bfs()
{
queue<NODE> Q;
NODE p(0,0,0,0); //初始结点入队
Q.push(p);
visited[0][0][0] = true;
while (!Q.empty()) //队列不空
{
NODE q = Q.front();
Q.pop();
if (q.x == A-1 && q.y == B-1 && q.z == C-1 && q.step <= limit) //找到满足条件的最短路
return q.step;
for (int i = 0; i<6; ++i) //对六个方向分别生成新节点
{
NODE next(q.x+dir[i][0], q.y+dir[i][1], q.z+dir[i][2], q.step+1);
if (!visited[next.x][next.y][next.z] //没被访问过
&& 0 <= next.x && next.x < A
&& 0 <= next.y && next.y < B
&& 0 <= next.z && next.z < C
&& puzzle[next.x][next.y][next.z] == 0)
{
visited[next.x][next.y][next.z] = true; //标记新节点被访问过
Q.push(next);
}
}
}
return -1;
}
int main()
{
ios::sync_with_stdio(false);
int kase;
cin >> kase;
while(kase--)
{
cin >> A >> B >> C >> limit;
memset(visited, 0, sizeof(visited));
for (int i = 0; i<A; ++i)
for (int j = 0; j<B; ++j)
for (int k = 0; k<C; ++k)
cin >> puzzle[i][j][k];
int ans = bfs();
cout << ans << endl;
}
return 0;
}
失败的DFS:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
using namespace std;
const int maxn = 55;
int puzzle[maxn][maxn][maxn];
bool visited[maxn][maxn][maxn];
int A, B, C, limit, minT;
int dir[6][3] =
{
-1, 0, 0,
1, 0, 0,
0, 0, -1,
0, 0, 1,
0, -1, 0,
0, 1, 0
};
void dfs(int x, int y, int z, int cnt)
{
if (cnt > limit) return;
if (x == A-1 && y == B-1 && z == C-1)
{
minT = min(minT, cnt);
return;
}
int nx,ny,nz;
for (int mov = 0; mov < 6; ++mov)
{
nx = x + dir[mov][0];
if (nx < 0 || nx >= A) continue;
ny = y + dir[mov][1];
if (ny < 0 || ny >= B) continue;
nz = z + dir[mov][2];
if (nz < 0 || nz >= C) continue;
if (!visited[nx][ny][nz] && puzzle[nx][ny][nz] == 0)
{
visited[nx][ny][nz] = true;
dfs(nx, ny, nz, cnt+1);
visited[nx][ny][nz] = false;
}
}
}
void solve()
{
if (puzzle[0][0][0] == 1)
{
cout << -1 << endl;
return;
}
visited[0][0][0] = true;
dfs(0, 0, 0, 0);
if(minT <= limit)
cout << minT << endl;
else cout << -1 << endl;
}
int main()
{
ios::sync_with_stdio(false);
int kase;
cin >> kase;
while(kase--)
{
cin >> A >> B >> C >> limit;
minT = 5000;
memset(visited, 0, sizeof(visited));
for (int i = 0; i<A; ++i)
for (int j = 0; j<B; ++j)
for (int k = 0; k<C; ++k)
cin >> puzzle[i][j][k];
solve();
}
return 0;
}