解題報告 Maze

2022-06-04 02:36:07 字數 4434 閱讀 7987

眾所周知(怎麼又是眾所周知),仙劍的迷宮是難走的要命,某人就在仙四的女羅巖困了很長時間。

我們可以把女羅巖的地圖抽象成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 ...