/* 知识:我被魔王抓走,城堡是A*B*C的立方体,即A个B*C的矩阵,我被关在(0,0,0)位置,出口在(A-1,B-1,C-1),魔王在T分钟内回到城堡,我每分钟能移动1个坐标。若 走到出口恰遇魔王,也算成功。请输出多少分钟可以离开,不能则输出-1 问题: 输入:第一行是1个正整数K,表名测试数据的数量。每组测试数据的第一行时4个正整数A,B,C和T(1<=A,B,C<=50,1<=T<=1000,)分别代表城堡的大小和魔王回来的时间 然后是A块输入数据(先是0块,1块,2块。。),每块输入数据有B行,每行有C个正整数,代表迷宫的布局,其中0代表路,1代表墙 输出:如果能离开,输出多少分钟,否则输出-1 输入: 1 3(3个) 3(行号) 4(列号) 20(魔王时间20秒) 0 1 1 1(0表示路,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 1 0 输出: 11 思路: 1 用mark[50][50][50]做标记数组,初始为false,已经搜索过则置为true,已经搜索过不再重复搜索 2 用设置坐标变换数组,进行状态的迁移 3 由于采用将(0,0,0)认为初始根节点,因为如果前面搜索到某状态,后面再次搜索到该状态必定所耗时间>=上一次搜索时间,因此后面索索过得一律不再搜索 4 用maze[][][]标识0路,1墙 5 广度优先遍历,必须用队列 6 设置初始节点时,不要忘记将其访问标记置为true 7 注意判断是否在城堡中,x <= a-1 而不是 x < a */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <queue> using namespace std; #define N 50 typedef struct Stat { int x,y,z;//坐标 int t;//从(0,0,0)到达该坐标的时间 }Stat;//保存当前节点的状态 int maze[N][N][N];//用于标识每一个坐标是0:路,1:墙 bool mark[N][N][N];//用于标识该坐标是否已经搜索过,false:未搜索过,true:搜索过,便于剪枝 int goNext[][3] = {1,0,0, -1,0,0, 0,1,0, 0,-1,0, 0,0,1, 0,0,-1};//用于进行下一次6个可达状态的遍历 queue<Stat> queueStat; //进行深度遍历,无需判断超时 int BFS(int a,int b,int c) { //只要队列不空,说明仍有状态需要遍历 while(!queueStat.empty()) { //弹出当前状态,进行状态迁移 Stat stat = queueStat.front(); queueStat.pop(); //遍历6种状态 int x,y,z; for(int i = 0 ; i < 6 ; i++) { x = stat.x + goNext[i][0]; y = stat.y + goNext[i][1]; z = stat.z + goNext[i][2]; //判断是否仍在围墙中 //易错,这里城堡的位置是不能为a,因为这是数组,这样做就超过了 //if(x < 0 || x > a || y < 0 || y > b || z < 0 || z > c) if(x <0 || x >= a || y < 0 || y >=b || z < 0 || z >= c ) { continue; } //如果已经遍历过,则跳过 if(true==mark[x][y][z]) { continue; } //如果下一个是墙,则跳过 if(1==maze[x][y][z]) { continue; } //更新状态 Stat statTemp; statTemp.x = x; statTemp.y = y; statTemp.z = z; statTemp.t = stat.t + 1;//所耗时间进行累加 //易错,更新剪枝状态 mark[x][y][z] = true; //将新状态放入队列 queueStat.push(statTemp); //判断是否已经到达终点,则返回其所耗时间 if(a-1==x && b-1==y && c-1==z) { return statTemp.t; } }//for }//while return -1;//如果一直没有找到,返回-1 } int main(int argc,char* argv[]) { int k; while(EOF!=scanf("%d",&k)) { //开始将队列清空 while(!queueStat.empty()) { queueStat.pop(); } while(k--) { int a,b,c,t; scanf("%d %d %d %d",&a,&b,&c,&t); for(int i = 0 ; i < a ; i++) { for(int j = 0 ; j < b ; j++) { for(int m = 0 ; m < c ; m++) { //输入迷宫中的当前点的状态:路还是墙,迷宫点的坐标有maze[i][j][m]下标标识 scanf("%d",&maze[i][j][m]); //易错,将状态标记 mark[i][j][m] = false; } } } //初始化起始节点信息 Stat stat; stat.x = 0; stat.y = 0; stat.z = 0; stat.t = 0; //易错,还要设置初始节点为已经遍历 mark[0][0][0] = true; //将起始节点信息放入状态队列 queueStat.push(stat); int iRes = BFS(a,b,c); //易错,需要将花费时间做判断 if(iRes <= t) { printf("%d\n",iRes); } else { printf("-1\n"); } } } system("pause"); getchar(); return 0; }