【搜索+拆点】魔鬼之城

魔鬼之城

源程序名            pils.???(pas, c, cpp)

可执行文件名        pils.exe

输入文件名          pils.in

输出文件名          pils.out

【问题描述】

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

 

1

2

3

4

5

1

3

3

6

7

11

2

3

2

1

1

3

3

3

2

2

1

1

4

2

1

2

2

1

例如在上图的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”。

【样例】

       pils.in                                        pils.out

       5 4                                             4

       3 3 6 7 11

       3 2 1 1 3

       3 2 2 1 1

       2 1 2 2 1

======================

应该算是一个裸宽搜的题目吧。

应该注意的是到达一个点的8个状态是不相同的,如果只定义一个hash判断的话,算法就相当于变成了贪心(不过可以过9个点)。

还有一个需要注意的内容,对于一个棋盘类跳棋的问题来说,我们还可以定义一个常值数组来判断下一步的路线,这样可以有效的减少代码量,与增加代码可读性。

======================

 

 
type
  re=record
       x,y,step,last:longint;
     end;
const
  dx:array[1..8]of longint=(-1,-1,-1,1, 1,1,0, 0);
  dy:array[1..8]of longint=(-1, 1, 0,1,-1,0,1,-1);
  
var
  n,m:longint;
  way:array[1..100,1..100]of longint;
  f:array[-13..114,-13..114,1..8]of boolean;
  h:array[0..200000]of re;
  
procedure init;
begin
  assign(input,'pils.in');
  assign(output,'pils.out');
  reset(input); rewrite(output);
end;

procedure terminate;
begin
  close(input); close(output);
  halt;
end;

procedure bfs;
var
  l,r:longint;
  x_,y_:longint;
  i:longint;
begin
  l:=0; r:=1;
  for i:=1 to 8 do
    f[1,1,i]:=false;
  h[1].x:=1; h[1].y:=1; h[1].step:=0; h[1].last:=0;
  repeat
    inc(l);
    l:=l mod 200000;
    for i:=1 to 8 do
      if i<>h[l].last then
      begin
        x_:=h[l].x+dx[i]*way[h[l].x,h[l].y];
        y_:=h[l].y+dy[i]*way[h[l].x,h[l].y];
        if f[x_,y_,i] then
          begin
            f[x_,y_,i]:=false;
            inc(r);
            r:=r mod 200000;
            h[r].x:=x_;
            h[r].y:=y_;
            h[r].step:=h[l].step+1;
            h[r].last:=i;
            if (x_=m)and(y_=n) then
              begin
                writeln(h[r].step);
                terminate;
              end;
          end;
      end;
  until l>=r;
end;

procedure main;
var
  i,j,K:longint;
begin
  readln(n,m);
  fillchar(f,sizeof(f),false);
  for i:=1 to m do
    for j:=1 to n do
      begin
        read(way[i,j]);
        for k:=1 to 8 do
          f[i,j,k]:=true;
      end;
  bfs;
  writeln('NEVER');
end;

begin
  init;
  main;
  terminate;
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值