胜利大逃亡
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 31687 Accepted Submission(s): 11749
Problem Description
Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会.
魔王住在一个城堡里,城堡是一个A*B*C的立方体,可以被表示成A个B*C的矩阵,刚开始Ignatius被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,现在知道魔王将在T分钟后回到城堡,Ignatius每分钟能从一个坐标走到相邻的六个坐标中的其中一个.现在给你城堡的地图,请你计算出Ignatius能否在魔王回来前离开城堡(只要走到出口就算离开城堡,如果走到出口的时候魔王刚好回来也算逃亡成功),如果可以请输出需要多少分钟才能离开,如果不能则输出-1.
魔王住在一个城堡里,城堡是一个A*B*C的立方体,可以被表示成A个B*C的矩阵,刚开始Ignatius被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,现在知道魔王将在T分钟后回到城堡,Ignatius每分钟能从一个坐标走到相邻的六个坐标中的其中一个.现在给你城堡的地图,请你计算出Ignatius能否在魔王回来前离开城堡(只要走到出口就算离开城堡,如果走到出口的时候魔王刚好回来也算逃亡成功),如果可以请输出需要多少分钟才能离开,如果不能则输出-1.
Input
输入数据的第一行是一个正整数K,表明测试数据的数量.每组测试数据的第一行是四个正整数A,B,C和T(1<=A,B,C<=50,1<=T<=1000),它们分别代表城堡的大小和魔王回来的时间.然后是A块输入数据(先是第0块,然后是第1块,第2块......),每块输入数据有B行,每行有C个正整数,代表迷宫的布局,其中0代表路,1代表墙.(如果对输入描述不清楚,可以参考Sample Input中的迷宫描述,它表示的就是上图中的迷宫)
特别注意:本题的测试数据非常大,请使用scanf输入,我不能保证使用cin能不超时.在本OJ上请使用Visual C++提交.
特别注意:本题的测试数据非常大,请使用scanf输入,我不能保证使用cin能不超时.在本OJ上请使用Visual C++提交.
Output
对于每组测试数据,如果Ignatius能够在魔王回来前离开城堡,那么请输出他最少需要多少分钟,否则输出-1.
Sample Input
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 1 0
Sample Output
11
题意:略
思路:(BFS)可以用三维数组来解决这题,但是我用的是二维,二维的思路就是,在读入的二维地图中,人在上下左右移动是可以通过x,y轴加减1来实现的,但前后移动就需要加减B来实现,就是单个块矩阵的宽,比如说,第一块的左上角的位置如果想要往前走一步,那么,走到的位置其实是第二块的左上角,在坐标上,就是y轴不变然后x轴向下移动B格。必要的时候还需要做一些剪枝,代码如下:
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<time.h>
#include<algorithm>
#include<cmath>
#include<stack>
#include<list>
#include<queue>
#include<map>
#define E exp(1)
#define PI acos(-1)
#define mod (ll)(1e9+9)
#define INF 0x3f3f3f3f;
#define MAX 40000
#define compare 0.00000001
#define exps 1e-8
#define fr_add(i,init,n) for(ll i = init ; i < n ; ++i)
#define fr_div(i,init,n) for(ll i = n ; i >= init ; --i)
//#define _CRT_SECURE_NO_WARNINGS
//#define LOCAL
using namespace std;
typedef long long ll;
typedef long double lb;
int p[2510][55], A, B, C, dir[7][2], Time, flag, mark;
struct point {
int x, y, step;
};
int bfs(struct point tp) {
queue<struct point> qu;
struct point temp, Front;
qu.push(tp);
flag = 0; mark = 0;
while (!qu.empty()) {
Front = qu.front();
fr_add(i, 0, 6) {
if (Front.x + dir[i][0] >= 0 && Front.x + dir[i][0] < B * A &&
Front.y + dir[i][1] >= 0 && Front.y + dir[i][1] < C &&
p[Front.x + dir[i][0]][Front.y + dir[i][1]] == 0) {
//假设起始点的坐标为 0,0,那么在x轴为B(或B-1)的倍数的时候
//是不可以直接在存入的地图中向上(或向下)走的,只能左右和前后走
//在纸上模拟一下就能明白,所以这里有两个条件避开这种情况
if ((Front.x + 1) % B == 0 && i == 1) continue;
if ((Front.x) % B == 0 && i == 0) continue;
p[Front.x + dir[i][0]][Front.y + dir[i][1]] = 1;
temp.x = Front.x + dir[i][0]; temp.y = Front.y + dir[i][1];
temp.step = Front.step + 1;
//如果广搜的到的步数已经大于魔王回来的时间,那么,即使能到门口输出的都是-1
if (temp.step > Time) {
mark = 1;
break;
}
qu.push(temp);
if (temp.x == A * B - 1 && temp.y == C - 1) {
flag = 1;
break;
}
}
}
if (flag == 1 || mark == 1) break;
qu.pop();
}
if (flag == 1) return qu.back().step;
else return -1;
}
int main(void)
{
#ifdef LOCAL
freopen("data.in.txt", "r", stdin);
freopen("data.out.txt", "w", stdout);
#endif
//ios::sync_with_stdio(false); cin.tie(0);
int t;
while (scanf("%d", &t) != EOF) {
while (t--) {
scanf("%d%d%d%d", &A, &B, &C, &Time);
// 代码里面的fr_add为宏定义的代码,其实就是一个for循环
// p二维存取地图
fr_add(i, 0, A*B) {
fr_add(j, 0, C) scanf("%d", &p[i][j]);
}
struct point start;
// 上下左右前后 为运动的方向
dir[0][0] = -1; dir[0][1] = 0;
dir[1][0] = 1; dir[1][1] = 0;
dir[2][0] = 0; dir[2][1] = -1;
dir[3][0] = 0; dir[3][1] = 1;
dir[4][0] = B; dir[4][1] = 0;
dir[5][0] = -B; dir[5][1] = 0;
start.step = 0, start.x = 0, start.y = 0;
p[0][0] = 1;
int res;
if (A*B == 1 && C == 1) res = 0;
//剪枝,从左上角走到右下角的最短途径就是绕着边长宽高的边各走一次
//假设立方内没有墙,那么走到右下角的最短路径就是A+B+C-3, 如果这个最短路径
//都要大于魔王回来的时间,那么可以直接输出-1了
else if (A + B + C - 3 > Time || p[A*B - 1][C - 1] == 1) res = -1;
else res = bfs(start);
printf("%d\n", res);
}
}
// end = clock();
// cout << "using tmie:" << (double)(end - start) / CLOCKS_PER_SEC * (1000) << "ms" << endl;
//system("pause");
return 0;
}