HDU P1253 胜利大逃亡 题解

HDU P1253 胜利大逃亡 题解

卡常数神题

Problem Description

Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会.

魔王住在一个城堡里,城堡是一个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++提交.

Output

对于每组测试数据,如果Ignatius能够在魔王回来前离开城堡,那么请输出他最少需要多少分钟,否则输出-1.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
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

1
11

从50*50*50的范围来看,显然dfs是不现实的,故采用bfs。那既然都用bfs了,当然是祭出spfa大法。

本题最大坑点在于,要么高度耦合,要么要内联,总之就是常数要优化到极致,不然就T,果断T。
说明已附在code里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
queue<int>qa,qb,qc;
bool d[60][60][60],v[60][60][60];
int ans[60][60][60],k,a,b,c,t;//50*50*50,故开60*60*60
inline void add(int aa,int bb,int cc)
{
qa.push(aa);
qb.push(bb);
qc.push(cc);//入队
v[aa][bb][cc]=true;//标记已用
}
inline void cut(int aa,int bb,int cc)
{
qa.pop();
qb.pop();
qc.pop();//出队
v[aa][bb][cc]=false;//取消标记
}
inline bool check(int aa,int bb,int cc,int sum)
{
if(!aa&&!bb&&!cc) return false;//1、不是起点
if(aa<0||bb<0||cc<0) return false;//2、不能向下越界
if(aa>=a||bb>=b||cc>=c) return false;//3、不能向上越界
if(v[aa][bb][cc]) return false;//4、不能是已经使用过的点
if(d[aa][bb][cc]) return false;//5、不能是墙
int tmp=ans[aa][bb][cc];
if(tmp&&sum>=tmp) return false;//6、目前计算所得值必须比已有最优解更优,否则走人
return true;//都通过了,合格了
}
inline void direct(int aa,int bb,int cc,int sum)
{
if(!check(aa,bb,cc,sum)) return;//如果不可行,不再计算
ans[aa][bb][cc]=sum;//更新值
if(!(aa==a-1&&bb==b-1&&cc==c-1)) add(aa,bb,cc);//如果被更新点不是终点,入队
}
void spfa()
{
while(!qa.empty())//当队列非空
{
int ta=qa.front(),tb=qb.front(),tc=qc.front();//取值
cut(ta,tb,tc);//出队
int sum=ans[ta][tb][tc]+1;//计算当前最优解
direct(ta-1,tb,tc,sum);
direct(ta+1,tb,tc,sum);
direct(ta,tb-1,tc,sum);
direct(ta,tb+1,tc,sum);
direct(ta,tb,tc-1,sum);
direct(ta,tb,tc+1,sum);//判断6个方向
}
}
int main()
{
freopen("in.txt","r",stdin);//文件读入,节省调试时输入的时间
scanf("%d",&k);//输入数据组数
while(k--)//循环k次
{
memset(v,0,sizeof(v));//初始化标记数组
memset(d,0,sizeof(d));//初始化地图
memset(ans,0,sizeof(ans));//初始化答案数组
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 z=0;z<c;z++)
scanf("%d",&d[i][j][z]);//输入
add(0,0,0);//将起点入队
spfa();//搜索
int answer=ans[a-1][b-1][c-1];//取终点答案,直接访问三维数组耗时太长,故新建一个变量用于保存
if(!answer||answer>t) printf("-1\n");//如果答案还是初始值,或答案大于规定时间,则无法
else printf("%d\n",answer);//输出可行答案
}
return 0;
}
--It's the end.Thanks for your read.--