zoukankan      html  css  js  c++  java
  • 解题报告 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.

     

     

     

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

  • 相关阅读:
    年纪大了,要学会控制自己的欲望
    java为什么要用类型擦除实现泛型?--c++,java,c# 的泛型是如何实现的
    面向对象:类的成员---只是特定(类的)命名空间的全局变量(函数)而已
    人的意志与自然法则—人的意志与人造事物
    所有的思考都有两个目的:建模降熵
    控制论、系统论与熵
    秩序(也常简称为序)是系统的本质特征之一
    控制论:基于全局信息和整体目标、整体规则的系统结构和状态维护
    人类社会的全部认识成果可以概括为三大领域的科学,即自然科学、社会科学和思维科学
    “逻辑”的古希腊词源
  • 原文地址:https://www.cnblogs.com/SueMiller/p/2216494.html
Copyright © 2011-2022 走看看