算例一【胜利大逃亡(九度OJ 1456)】
-
题目描述
-
解题思路
①这是一个三维迷宫,每一步有上下左右前后六个方向
②为了能够更一般的考虑搜索的问题,我们常在搜索问题中指明某种状态,从而使搜索问题变为对状态的搜索,因此这里我们转化为对状态(x,y,z,t)的搜索
③由于任一状态(x,y,z,t)可以扩展至(x+1,y,z,t+1),(x-1,y,z,t+1),(x,y+1,z,t+1),(x,y-1,z,t+1),(x,y,z+1,t+1),(x,y,z-1,t+1)六个状态,所以这个过程可以看做是由根节点衍生出6个子节点的过程,最终答案也在这棵树中,我们要做的就是用广度优先搜索遍历这棵树
④考虑复杂度!走10步就达到了6^10,所以我们必须排除一些情况(剪枝)
⑤剪枝情况
i)先查找到的状态深度必不大于后查找到的状态深度(深度与状态中耗时成正比),所以a->b之后,b->a就不用考虑了
ii)到达任意一个中间结点所用的时间都是起点到达这个结点的最短时间。如果t不是从起点到(x,y,z)的最短时间,那么此子树上的状态不用考虑
-
解题代码
#include <stdio.h>
#include <iostream>
#include <queue>
using namespace std;
struct N{
int x,y,z,t;
void Set(int x1,int y1,int z1,int t1){//设置N的信息
x=x1;
y=y1;
z=z1;
t=t1;
}
};
queue<N> Q;
int a,b,c,T;
bool mark[55][55][55];//标记该点是否已被访问,值=1时,该点的t就是从起点到达该点的最短时间
int Map[55][55][55];//地图信息,记录通路/墙的状态
int T_m;
bool Isfinish(N tmp){//判断是否结束
if(tmp.x==a-1&&tmp.y==b-1&&tmp.z==c-1){
T_m=tmp.t;
return true;
}else
return false;
}
void go(N p){//步行函数,向6个方向试探
N tmp;
//left
if(p.x-1>=0&&Map[p.x-1][p.y][p.z]==0&&mark[p.x-1][p.y][p.z]==0){//若没越界&&是通路&&还没标记,则走(入队列并标记)
tmp.Set(p.x-1,p.y,p.z,p.t+1);
Q.push(tmp);
mark