解题报告 Maze

Maze

【题目描述】

众所周知(怎么又是众所周知),仙剑的迷宫是难走的要命,某人就在仙四的女罗岩困了很长时间。

我们可以把女罗岩的地图抽象成n*n的地图,我们现在在(1,1)处,而出口在(n,n)。每次行动只能向上下左右移动一格。图中有M个机关,只有打开某个机关之后,与该机关相对应的地方才可以行走。当然,地图中还会有小怪兽,他们能够监视着他所在地区以及上下左右共五个方格,我们不愿意与他们战斗(为了节省时间),所以他们能监视到的地方不可以行走。同样的,地图上的障碍物处也不能经过。

我们需要求出从起点到终点的最少步数。

【输入格式】

1行,两个整数N, M。表示地图大小为N*N机关的数量为M

2-N+1行,每行N个整数,每个整数i可能是0-1-2或者一个正整数。i=0表示该位置为一块空地,i=-1表示该位置为一个障碍物,i=-2表示该位置为一个小怪兽。如果i是一个属于[1,M]的正整数,则表示该位置为一个机关,其编号为i。如果i是一个大于M的正整数,则表示该位置为一个机关控制区域,它由编号为i-M机关控制

【输出格式】

一个整数,为走出迷宫所需的最少的步数。

【输入样例】

6 2

0 0 0 -2 -1 2

-1 0 0 0 -1 0

-2 0 0 0 3 3

-2 0 0 -1 -1 4

0 -1 0 0 -1 0

1 0 0 0 -1 0

【输出样例】

24

样例说明

地图如下图,S为入口,T为目标,黑色的单元格为障碍物。每个E表示一个小怪兽(E)小怪兽的监视范围。K1表示机关1K2表示机关2D1表示机关1控制区域D2表示机关2控制区域

最优的路线为(1,1) →(1,2) →(2,2) →(2,3) →(3,3) →(4,3) →(5,3) →(6,3) →(6,2) →(6,1)(破坏供电1) →(6,2) →(6,3) →(5,3) →(4,3) →(3,3) →(3,4) →(3,5) →(3,6) →(2,6) →(1,6)(破坏供电2) →(2,6) →(3,6) →(4.6) →(5,6) →(6,6)

数据规模

1<=N<=50

0<=M<=16

 

 

 

这是一个经典的模型,需要记录地图的迷宫问题。

首先,迷宫问题一般都是 BFS ,这个当然也不例外。

然后,平常做迷宫问题的时候,只需要在队列中记录一下横纵坐标就可以了,但这种问题,还需要记录一下拿了那些钥匙,当然,是用位运算来记录的。一共有 16 把钥匙,也就最大是 2^16-1 ,所以可以记录的下。

然后,当扩展时,怪兽及怪兽能看到的一定不能扩展,需要钥匙的,如果有钥匙就可以扩展,是钥匙的,用位运算把它加上去。

然后,然后就是这样。

 

晒一下 (XMC)的代码。

const

  bx:array[1..4] of integer=(1,-1,0,0);

  by:array[1..4] of integer=(0,0,1,-1);

type

  ll=record

    x,y:integer;

    d,z:longint;

  end;

var

 i,j,k,n,m:longint;

 v:array[0..51,0..51,0..65536] of boolean;

 q:array[0..1000001] of ll;

 map:array[0..51,0..51] of integer;

 aa,x,y,d,z,xx,yy,head,tail,zz:Longint;

procedure init;

  begin

    readln(n,m);

    fillchar(map,sizeof(map),0);

    for i:=1 to n do

      for j:=1 to n do

        begin

          read(aa);

          if map[i,j]<>-1 then map[i,j]:=aa;

          if aa=-2 then

            begin

              map[i,j]:=-1;

              for k:=1 to 4 do

                begin

                  xx:=i+bx[k];

                  yy:=j+by[k];

                  if (xx in[1..n]) and (yy in [1..n]) then

                    map[xx,yy]:=-1;

                end;

            end;

        end;

  end;

procedure main;

  begin

    v[1,1,0]:=true;

    head:=0;

    tail:=1;

    q[1].x:=1;

    q[1].y:=1;

    q[1].z:=0;

    q[1].d:=0;

    while head<>tail do

      begin

        if head=1000000 then head:=1 else inc(head);

        x:=q[head].x;

        y:=q[head].y;

        d:=q[head].d;

        z:=q[head].z;

        for i:=1 to 4 do

          begin

            xx:=x+bx[i];

            yy:=y+by[i];

            if (xx in [1..n]) and (yy in [1..n]) and (map[xx,yy]>=0) and (not v[xx,yy,z])then

              begin

 

                if (xx=n) and (yy=n) then

                  begin

                    writeln(d+1);

                    close(input);

                    close(output);

 

 

                    halt;

                  end;

 

                if (map[xx,yy]=0) and (not (v[xx,yy,z])) then

                  begin

                    v[xx,yy,z]:=true;

                    if tail=1000000 then tail:=1 else inc(tail);

                    q[tail].x:=xx;

                    q[tail].y:=yy;

                    q[tail].z:=z;

                    q[tail].d:=d+1;

                    continue;

                  end;

                if (map[xx,yy]<=m) and

                ((z and (1<<(map[xx,yy]-1))=0) or

                ((z and (1<<(map[xx,yy]-1))<>0) and  (not v[xx,yy,z]))) then

                  begin

                    if z and (1<<(map[xx,yy]-1))=0 then zz:=z+(1<<(map[xx,yy]-1))

                      else zz:=z;

                    v[xx,yy,zz]:=true;

                    if tail=1000000 then tail:=1 else inc(tail);

                    q[tail].x:=xx;

                    q[tail].y:=yy;

                    q[tail].z:=zz;

                    q[tail].d:=d+1;

                    continue;

                  end;

                if (map[xx,yy]>m) and (z and (1<<(map[xx,yy]-m-1))<>0) and (not v[xx,yy,z]) then

                  begin

                    v[xx,yy,z]:=true;

                    if tail=1000000 then tail:=1 else inc(tail);

                    q[tail].x:=xx;

                    q[tail].y:=yy;

                    q[tail].z:=z;

                    q[tail].d:=d+1;

                    continue;

                  end;

              end;

     end;

    end;

  end;

begin

  assign(input,'maze.in');reset(input);

  assign(output,'maze.out');rewrite(output);

  init;

  main;

  close(input);

  close(output);

end.

 

 

 

另,存稀疏图不一定非要用邻接表,也可以用边表。(也就是开一个边数那么大的数组,存每一条边的起点、终点、权值,这个方法比邻接表要慢,但是他比邻接表好写,还省内存(如果你用正常的链表而不是模拟链表的话当我没说),对于我这种邻接表经常写挂的人来说很好用)

原文地址:https://www.cnblogs.com/SueMiller/p/2216494.html