眾所周知(怎麼又是眾所周知),仙劍的迷宮是難走的要命,某人就在仙四的女羅巖困了很長時間。
我們可以把女羅巖的地圖抽象成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 20 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 ,這個當然也不例外。
然後,平常做迷宮問題的時候,只需要在佇列中記錄一下橫縱座標就可以了,但這種問題,還需要記錄一下拿了那些鑰匙,當然,是用位運算來記錄的。一共有 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;
vari,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<
((z and (1<0) and (not v[xx,yy,z]))) then
begin
if z and (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<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.
另,存稀疏圖不一定非要用鄰接表,也可以用邊表。(也就是開乙個邊數那麼大的陣列,存每一條邊的起點、終點、權值,這個方法比鄰接表要慢,但是他比鄰接表好寫,還省記憶體(如果你用正常的鍊錶而不是模擬鍊錶的話當我沒說),對於我這種鄰接表經常寫掛的人來說很好用)
POJ 2157 Maze 解題報告
題目大意是給你一張n m的迷宮,大寫字母a e代表的是門,小寫字母a e對應的是其大寫字母門的鑰匙,如果一扇門在一張圖里有多個鑰匙,那麼必須都找到這些鑰匙才能開啟這扇門,x代表是牆壁,代表此處為空可以行走,詢問是否可以從s走到g。剛開始思路想錯了,想著乙個點最多被訪問4次,然後就自信的寫完了,手出了...
Block Voting 解題報告
這道題做的有點狼狽,效率不高,差一點就tle的ac了。看status裡的,ac的時間大多數都是0ms的。肯定有乙個更有效率的演算法的。下面說下我的狼狽演算法。出處 http acm.jlu.edu.cn joj showproblem.php?pid 1223 問題描述 求每個party的權值。第i...
Safebreaker 解題報告
又是吉林大學一道acm題目,題目很簡單,直接暴力解決。出處 http acm.jlu.edu.cn joj showproblem.php?pid 1718 問題描述 對乙個給定數0000 9999 根據一系列猜測,判斷這個數是否存在,存在的話,是否唯一 例如 3321,給定數 作出猜測,1223 ...