hdu 1253 胜利大逃亡

  题目链接:hdu 1253,题目大意:从一个立方体的左下角走到右上角(两点间的连线为长方体的体对角线)的最少时间(步数),走不到或者最少时间达不到要求输出 -1,否则输出该时间。

  因为要求"最少"之类的,所以很容易想到广搜,没错,这是 bfs 的裸题,只是它的状态数是个三维数组,转移的状态(方向)也从二维数组的4个变成了6个而已,但原理是一样的,直接广搜即可,只是这题的坑未免也太不人性化了,我 wa了几发看了讨论区后才知道原来起点不管是不是墙都不用管(继续搜),只需看终点即可。

  首先是第一个版本的代码,用个三维的 dp 数组来记录从起点出发到当前结点的时间/步数,比较清晰:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<queue>
 5 using namespace std;
 6 #define For(i,s,t)    for(int i=s; i<t; ++i)
 7 const int inf= 0x2fffffff;
 8 int a,b,c,T;
 9 int f[60][60][60], dp[60][60][60];
10 
11 int dir[8][3]= {{0,0,1},{0,1,0},{-1,0,0},{1,0,0},{0,-1,0},{0,0,-1}};
12 
13 struct node{
14     int x,y,z;
15     node(int x=0, int y=0, int z=0): x(x),y(y),z(z) {}
16 };
17 
18 void solve(){
19     scanf("%d%d%d%d",&a,&b,&c,&T);
20     For(i,0,a+2)    For(j,0,b+2)    For(k,0,c+2) {
21         f[i][j][k]= 1;    dp[i][j][k]= inf;
22     }
23     For(i,1,a+1)    For(j,1,b+1)    For(k,1,c+1)
24         scanf("%d",f[i][j]+k);
25     
26     //如果终点是墙就永远出不了,(这题挺坑的,起点不管是不是墙都不要紧) 
27     //或者从起点到终点的最短直线距离比 T大的话也出不了,是个很重要的剪枝 
28     if(f[a][b][c]==1 || a+b+c-3 > T)    {    puts("-1");     return ;    }
29 
30     queue<node> q;
31     q.push(node(1,1,1));
32     dp[1][1][1]= 0;
33     while(q.size()){
34         node p= q.front();    q.pop();
35         for(int k=0; k<6; ++k){
36             int dx= p.x+dir[k][0], dy= p.y+dir[k][1], dz= p.z+dir[k][2];
37             if(f[dx][dy][dz]!= 1 && dp[dx][dy][dz]== inf){
38                 dp[dx][dy][dz]= dp[p.x][p.y][p.z]+1;
39                 q.push(node(dx,dy,dz));
40             }
41         }
42     }
43     //算出到达终点的时间后,还需判断是否满足题意 
44     if(dp[a][b][c] > T)      puts("-1");
45     else    printf("%d\n",dp[a][b][c]);
46 }
47 
48 int main(){
49     int k;
50     scanf("%d",&k);
51     while(k--)    solve();
52     return 0;
53 }
View Code

  然后第二个版本的,省去了dp数组,改用结点的结构体里增多一个变量来记录时间:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<queue>
 5 #include<algorithm>
 6 using namespace std;
 7 #define For(i,s,t)    for(int i=s; i<t; ++i)
 8 const int inf= 0x2fffffff;
 9 int a,b,c,T;
10 int f[60][60][60];
11 
12 int dir[8][3]= {{0,0,1},{0,1,0},{-1,0,0},{1,0,0},{0,-1,0},{0,0,-1}};
13 
14 struct node{
15     int x,y,z,t;
16     node(int x=0, int y=0, int z=0, int t= inf): x(x),y(y),z(z),t(t) {}
17     bool operator ==(const node &n2) const {
18         return x==n2.x && y==n2.y && z==n2.z;
19     }
20 };
21 
22 void solve(){
23     scanf("%d%d%d%d",&a,&b,&c,&T);
24     For(i,0,a+2)    For(j,0,b+2)    For(k,0,c+2)
25         f[i][j][k]= 1;
26     For(i,1,a+1)    For(j,1,b+1)    For(k,1,c+1)
27         scanf("%d",f[i][j]+k);
28     
29     //如果终点是墙就永远出不了,(这题挺坑的,起点不管是不是墙都不要紧) 
30     //或者从起点到终点的最短直线距离比 T大的话也出不了,是个很重要的剪枝 
31     if(f[a][b][c]==1 || a+b+c-3 > T)    {    puts("-1");     return ;    }
32     
33     node ed(a,b,c);
34     queue<node> q;
35     q.push(node(1,1,1,0));
36     while(q.size()){
37         node p= q.front();    q.pop();
38         if(p == ed)        ed.t= min(ed.t,p.t);
39         for(int k=0; k<6; ++k){
40             int dx= p.x+dir[k][0], dy= p.y+dir[k][1], dz= p.z+dir[k][2];
41             if(f[dx][dy][dz]!= 1){
42                 q.push(node(dx,dy,dz,p.t+1));
43                 f[dx][dy][dz]= 1;
44             }
45         }
46     }
47     //算出到达终点的时间后,还需判断是否满足题意
48     if(ed.t > T)      puts("-1");
49     else    printf("%d\n",ed.t);
50 }
51 
52 int main(){
53     int k;
54     scanf("%d",&k);
55     while(k--)    solve();
56     return 0;
57 }
View Code

  方向数组 dir[][][] 果然还是把 x,y,z 封装在一维里更好一些~~

你可能感兴趣的:(HDU)