洛谷P1301 魔鬼之城 题解

想找原题请点击这里:传送门

题目描述
在一个被分割为N*M个正方形房间的矩形魔鬼之城中,一个探险者必须遵循下列规则才能跳跃行动。他必须从(1, 1)进入,从(N, M)走出;在每一房间的墙壁上都写了一个魔法数字,是1~13之内的自然数;探险者可以想像出8个方向中的任何一个(水平或垂直或对角线方向),随后他就可以作一次空间跳跃穿过这一方向上的连续的X个房间,其中X是他原来所在房间的魔法数字。但如果在这一方向上的房间数小于X,则他不作任何跳跃,而必须想像另一个方向。同时,探险者不能作连续两次相同方向的跳跃。



例如在上图的5*4的魔鬼之城中,如果探险者现在所在的位置是(3, 3),那么通过依次空间跳跃他可以到达下列房间中的一个:(1, 1),(3, 1),(1, 3),(5, 1),或(5, 3)。另外,如果他要用两次跳跃从(5, 4)到达(3, 2),则他不能首先跳到(4, 3)(因为这样他第二次跳跃的方向将和第一次相同,而这是不允许的)。所以他必须先跳跃到(2, 1)。

请你写一个程序,对给定的地图,算出探险者至少需要跳跃多少步才能离开魔鬼之城。

输入格式
一行给出N,M(都不超过100);

下来有M行,每行为N个自然数,表示对应房间中的魔法数字。

输出格式
出最小步数,如果探险者无法离开魔鬼之城,请输出“NEVER”。

输入输出样例
输入 #1复制
5 4
3 3 6 7 11
3 2 1 1 3
3 2 2 1 1
2 1 2 2 1
输出 #1复制
4

(图片请自行到原网站查看)

这道题乍一看跟迷宫最短路径问题很相似所以初步印象首选bfs,然后我们做进一步分析:

我们经过分析又得知两次不可能连续走同一方向,所以我们在进行bfs时还需要定义一变量记录上一步跳跃方向以防止连续两次方向相同。

我们经过分析又得知如果同一个点在bfs过程中被访问了两次相同方向,那么这一行为必定是没有贡献的(相当于走了一遍走过的路所以也就不需要重新走一遍了)

所以基于上述分析我们可得知我们可以对每一个点的八个不同方向建立bool数组来记录是否被访问过。

代码实现:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m;
 4 int a[105][105];
 5 bool b[105][105][11];
 6 int ans=-1;
 7 int t;        //多少步 
 8 int vis;    //多少个格子被访问 
 9 int v;        //这一个格子上的数 
10 struct node{
11     int x;
12     int y;
13     int direct;        //1表示向左上然后逆时针
14 };
15 node tmp;
16 queue < pair<node,int> > q;
17 void bfs(int xx,int yy){
18     q.push(make_pair((node){xx,yy,0},0));
19     while(!q.empty()){
20         tmp=q.front().first;
21         t=q.front().second;
22         q.pop(); 
23         if(tmp.x==n&&tmp.y==m) {ans=t;break;}    
24         if(b[tmp.x][tmp.y][tmp.direct]) continue;
25         b[tmp.x][tmp.y][tmp.direct]=true;
26         vis++;
27         v=a[tmp.x][tmp.y]; 
28         if(tmp.x-v>=1){
29             if(tmp.y-v>=1&&!b[tmp.x-v][tmp.y-v][1]&&tmp.direct!=1){
30                 q.push(make_pair((node){tmp.x-v,tmp.y-v,1},t+1));
31                 vis++;
32             }
33             if(tmp.y+v<=m&&!b[tmp.x-v][tmp.y+v][3]&&tmp.direct!=3){
34                 q.push(make_pair((node){tmp.x-v,tmp.y+v,3},t+1));
35                 vis++;
36             }
37             if(!b[tmp.x-v][tmp.y][2]&&tmp.direct!=2){
38                 q.push(make_pair((node){tmp.x-v,tmp.y,2},t+1));
39                 vis++;
40             }
41         }
42         if(tmp.x+v<=n){
43             if(tmp.y+v<=m&&!b[tmp.x+v][tmp.y+v][5]&&tmp.direct!=5){
44                 q.push(make_pair((node){tmp.x+v,tmp.y+v,5},t+1));
45                 vis++;
46             }
47             if(tmp.y-v>=1&&!b[tmp.x+v][tmp.y-v][7]&&tmp.direct!=7){
48                 q.push(make_pair((node){tmp.x+v,tmp.y-v,7},t+1));
49                 vis++;
50             }
51             if(!b[tmp.x+v][tmp.y][6]&&tmp.direct!=6){
52                 q.push(make_pair((node){tmp.x+v,tmp.y,6},t+1));
53                 vis++;
54             }
55         }
56         if(tmp.y-v>=1&&!b[tmp.x][tmp.y-v][8]&&tmp.direct!=8){
57             q.push(make_pair((node){tmp.x,tmp.y-v,8},t+1));
58             vis++;
59         }
60         if(tmp.y+v<=m&&!b[tmp.x][tmp.y+v][4]&&tmp.direct!=4){
61             q.push(make_pair((node){tmp.x,tmp.y+v,4},t+1));
62             vis++;
63         }
64     }
65     return ;
66 }        
67 int main(){
68     scanf("%d%d",&n,&m);
69     for(register int i=1;i<=m;i++){
70         for(register int j=1;j<=n;j++){
71             scanf("%d",&a[j][i]);
72         }
73     }
74     bfs(1,1);
75     if(ans>0){
76         printf("%d",ans);
77     }
78     else{
79         printf("NEVER");
80     }
81     return 0;
82 }

 

posted @ 2020-02-27 00:18  Robertspot  阅读(159)  评论(0编辑  收藏  举报