【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原创,转载请注明出处)