题目描述:
一个A*B*C的立方体,Ignatius被困在其中(0,0,0)的位置,离开立方体的门在(A-1,B-1,C-1)位置。在给定时间T内,若Ignatius能够离开立方体,则逃亡成功。如果可以输出逃亡时间,否则输出-1.
输入:
输入数据的第一行是一个正整数K,表名测试数据的数量。每组测试数据的第一行是四个正整数A,B,C和T,(1<=A,B,C<=50,1<=T<=1000),它们分别代表立方体的大小和规定时间,然后是A块输入数据(先是第0块,然后是第1块,第2块......),每块输入数据有B行,每行有C个正整数,代表立方体的布局,其中0代表路,1代表墙。
输出:
对于每组测试数据,如果Ignatius能在T时间内(包含T)离开,则输出需要的时间,否则输出-1.
样例输入:
1
3 3 4 20
0 1 1 1
0 0 1 1
0 1 1 1
1 1 1 1
1 0 0 1
0 1 1 1
0 0 0 0
0 1 1 0
0 1 000
样例输出:
11
示例代码:
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
public static int costTime(boolean[][][] isVisited,boolean[][][] isWay,int A,int B,int C){
Queue<Point_time> pt = new LinkedList<>();//为了实现各个状态按其被查找到的顺序依次进行扩展,
// 使用队列将每次扩展得到的新结点加入队列,待排在其之前的状态都被扩展完成之后,该状态才能得到扩展
Point_time start = new Point_time(0, 0, 0, 0);
pt.offer(start);
while (!pt.isEmpty()){
Point_time ptToexplore = pt.peek();
int x = ptToexplore.x;
int y = ptToexplore.y;
int z = ptToexplore.z;
isVisited[x][y][z] = true;
int t = ptToexplore.t;
if (x==A-1&&y==B-1&&z==C-1){return t;}
if (!isWay[x][y][z]){pt.poll();continue;}//如果是墙,则不需要扩展,将此结点从队列中删去
int x1 = x - 1;
int x2 = x + 1;
int y1 = y - 1;
int y2 = y + 1;
int z1 = z - 1;
int z2 = z + 1;
t++;
if (x > 0) {
if (!isVisited[x1][y][z]){//当加入某一结点时,先判断此结点有没有被扩展过。
// 扩展过的结点t值<=将要扩展的此结点值(在树的同一层时相等,在不同层时,小于),故若扩展过,不将此结点加入队列,即进行剪枝
pt.offer(new Point_time(x1, y, z, t));}}
if (x<A-1) {
if (!isVisited[x2][y][z]){
pt.offer(new Point_time(x2, y, z, t));}}
if (y > 0) {
if (!isVisited[x][y1][z]){
pt.offer(new Point_time(x, y1, z, t));}}
if (y<B-1) {
if (!isVisited[x][y2][z]){
pt.offer(new Point_time(x, y2, z, t));}}
if ( z> 0) {
if (!isVisited[x][y][z1]){
pt.offer(new Point_time(x, y, z1, t));}}
if (z<C-1) {
if (!isVisited[x][y][z2]){
pt.offer(new Point_time(x, y, z2, t));}}
pt.poll();//将拓展过的结点从待处理队列中删除
}
return -1;//若遍历完所有在queue中的结点,仍没有访问到[A-1][B-1][C-1],则返回-1
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int count = scanner.nextInt();
for (int cnt = 0; cnt < count; cnt++) {
int A = scanner.nextInt();
int B = scanner.nextInt();
int C = scanner.nextInt();
boolean[][][] isWay = new boolean[A][B][C];//记录每个点是否是路
boolean[][][] isVisited = new boolean[A][B][C];//记录每个点是否被访问过,
// 若结点被访问过,则不再进行扩展,实际上达到了剪枝的目的
int T = scanner.nextInt();
for (int a = 0; a < A; a++) {
for (int b = 0; b < B; b++) {
for (int c = 0; c < C; c++) {
isWay[a][b][c] = scanner.nextInt() == 0;
}
}
}
int cost_time = costTime(isVisited,isWay,A,B,C);
if (cost_time<=T){System.out.println(cost_time);}
else {System.out.println(-1);}
}
}
}
}
public class Point_time {
int x,y,z;//三维空间中点的坐标
int t;//从[0][0][0]到该点的时间t
public Point_time(int x,int y,int z,int t){
this.x = x;
this.y = y;
this.z = z;
this.t = t;
}
}