【Nov 11 P4,分层BFS】潜入辛迪加

 

【题目描述】(来源:BYVoid的WOW模拟赛Stage.3 P4)
“我们最新的研究成果《毒药研究方案》被可恶的辛迪加间谍偷走了!”作为拉文霍德的一员,你一定
感到很震惊,因为它是我们最尖端的科研人员的一年的研究成果。被辛迪加获得,我们可能会有灭顶之灾。
狡猾的辛迪加为了躲避我们的追杀,他们并没有把《毒药研究方案》带回激流堡,而是藏了起来。但是终究
是我们技高一筹,通过购买侏儒的最新研究成果“静电放射探测器”,我们已经发现了他们的藏身之地。原来
他们早就在奥特兰克山脉的地下修建了一个巨大的城市,现在,他们就把《毒药研究方案》放在了城市的最
深处。更好的消息是,我们已经发现了地下城的入口。作为一名出色的盗贼,你要学会以彼之道,还施彼身
——把《毒药研究方案》偷回来。然而辛迪加布置了严密的防御,更糟糕的是,他们从地精购买了电磁监视器。
无论你的潜行技巧有多么高明,只要一接近它,就会出发警报。只有破坏它的供电系统,才能电磁监视器悄
无声息得失效。
现在, “静电放射探测器”已经为我们生成了一张地图,它可以告诉你整个地下城的布局结构,包括每
一个电磁监视器的位置,及其供电装置的位置。辛迪加的地下城可以被描述为一个N*N 的表格,城市的入口
在(1,1)处,目标《毒药研究方案》在(N,N)处。每个单元格可能是一片空地、一个障碍物、一个辛迪加卫
士、一个电磁监视器、或者一个的供电装置。从入口处开始,每步你只能向上、下、左、右移动到相邻的一个
单元格,不可以停留在原地。你只能进入空地,或者失去供电系统的电磁监视器的位置,或者摧毁供电装置。
你不能移动到障碍物上,也不能进入辛迪加卫士的视线中。辛迪加卫士可以监视自己所在单元格以及上下左右
共五格的位置,而且他们的视线可以重叠。你不能杀死辛迪加卫士,也不能被他们发现。每个电磁监视器的供
电装置可能存在,也可能无法破坏或者根本不存在。一个供电装置也可能会对应零个、一个或多个电磁监视器,
意味着摧毁它,对应的所有电磁监视器都会失效。(1,1)和(N,N)一定是可以通行的。拉文霍德要求你在执行
任务之前首先给出一个计划书,即要求算出至少一共需要多少步,才能拿到我们的《毒药研究方案》。
【输入格式】
第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表示供电装置 1,K2表示供电装置 2。D1表示供电装置为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。这时可以使用位运算对钥匙进行Hash求解。

      注意对各种障碍物的处理。如果是士兵则上下左右四个方向都要标记。

 

参考代码:

 

program syndicate;
  const
    dx:array[1..4]of integer=(0,0,-1,1);
    dy:array[1..4]of integer=(1,-1,0,0);
  type l=record
    x,y,dist:integer;
    ft:array[1..16]of boolean;
  end;
  var
    map:array[-1..51,-1..51]of integer;
    ff:array[1..16]of boolean;
    v:array[0..100000,0..50,0..50]of boolean;  //三维的标记数组
    n,m,i,j:longint;
    f,s,xx,yy:longint;
    d:array[1..1000000]of l;
    k:longint;
  begin
    readln(n,m);
    for i:=1 to n do
      for j:=1 to n do
        begin
          read(k);
          if k=-2 then  //处理士兵
            begin
              map[i,j]:=-2;
              map[i+1,j]:=-2;
              map[i-1,j]:=-2;
              map[i,j-1]:=-2;
              map[i,j+1]:=-2;
            end;
          if map[i,j]<>-2 then map[i,j]:=k;
        end;
    f:=1;
    s:=1;
    d[1].x:=1;
    d[1].y:=1;
    fillchar(v,sizeof(v),false);
    v[0,1,1]:=true;
    while f<=s do
      begin
        for i:=1 to 4 do
          begin
            xx:=d[f].x+dx[i];
            yy:=d[f].y+dy[i];
            k:=0;
            for j:=1 to m do
              begin
                ff[j]:=d[f].ft[j];
                if ff[j] then k:=k+1<<(j-1);  //位运算记录钥匙
              end;
            if(xx>0)and(xx<=n)and(yy>0)and(yy<=n)then
              begin
                if(map[xx,yy]>0)and(map[xx,yy]<=m) then
                  if not v[k,xx,yy] then
                    begin
                      v[k,xx,yy]:=true;
                      inc(s);
                      k:=k+1<<(map[xx,yy]-1);
                      if s>1000000 then s:=1;
                      ff[map[xx,yy]]:=true;
                      d[s].ft:=ff;
                      d[s].dist:=d[f].dist+1;
                      d[s].x:=xx;
                      d[s].y:=yy;
                      v[k,xx,yy]:=true;
                    end;
                if map[xx,yy]>m then
                  if(ff[map[xx,yy]-m])and(not v[k,xx,yy])then
                    begin
                      v[k,xx,yy]:=true;
                      inc(s);
                      if s>1000000 then s:=1;
                      d[s].ft:=ff;
                      d[s].dist:=d[f].dist+1;
                      d[s].x:=xx;
                      d[s].y:=yy;
                    end;
                if map[xx,yy]=0 then
                  if not v[k,xx,yy] then
                    begin
                      v[k,xx,yy]:=true;
                      inc(s);
                      if s>1000000 then s:=1;
                      d[s].ft:=ff;
                      d[s].dist:=d[f].dist+1;
                      d[s].x:=xx;
                      d[s].y:=yy;
                    end;
                if(xx=n)and(yy=n)then
                  begin
                    writeln(d[s].dist);
                    close(input);
                    close(output);
                    halt;
                  end;
              end;
          end;
        inc(f);
        if f>1000000 then f:=1;
      end;
    writeln('http://www.cnblogs.com/saltless');
  end.

 

本文地址:http://www.cnblogs.com/saltless/archive/2010/11/15/1877353.html

(saltless原创,转载请注明出处)

posted on 2010-11-15 08:25  saltless  阅读(611)  评论(0编辑  收藏  举报

导航