費解的開關(vijos1197)

2021-05-31 22:55:21 字數 2307 閱讀 3451

演算法:搜尋

很經典的一道題,也是很考驗選手水平的一道題。

本題總共有兩種方法:

費解的開關

題目本身是乙個經典的廣搜問題,題目讀完後可以立即寫出乙個廣搜的程式。但是,這只能通過30%的小資料;當n=500時做500次普通的廣搜必然超時。或許,有人曾想過提高每一次廣搜的效率,比如採用雙向搜尋。連雙向搜尋都已經想到了,為何不嘗試一下反向搜尋呢?

程式讀入資料前我們需要一次廣搜作為初始化。我們可以從最終狀態出發,用一次廣搜倒推出所有前6步的狀態。這樣,所有能夠在6步以內完成的狀態我們都求出來了。以後讀入資料,問到哪個答哪個,如果讀入的狀態不在我們求出的狀態中直接輸出「-1」就行了。

在程式實現時,我們可以把狀態壓縮成25位的二進位制數並用十進位制儲存。使用位運算將使得程式執行得更快。xor有乙個很好的特性,乙個boolean值與true進行xor運算後將取反,與false進行xor運算後值不變。於是,對二進位制數a的右數第4個數字取反,我們可以用a xor (1 shl 3)來完成。你完全可以把25種狀態變化所對應的要xor的值先算出來。

有乙個小地方值得注意:第三個資料出現了輸出為0的情況,即某個初始狀態全部為1。很多人在這裡沒有處理好。

補充疾風劍客提供了乙個相當快的演算法,它的演算法能在相當短的時間裡算出給定狀態到最終狀態所需要的步數:對於每個狀態,演算法只需要列舉第一行改變哪些燈的狀態,只要第一行的狀態固定了,接下來的狀態改變方法都是唯一的:每一行需要改變狀態的位置都在上一行中不亮的燈的正下面,因為只有這樣才能使上一行的燈全亮。我們列舉第一行的狀態改變方法(共2^5種),對於每種方法都依次改變下面幾行的狀態使上面一行燈全亮。到最後一行我們需要判斷是否最後一行也恰好全亮,並更新最小步數。好像這個演算法能在0ms內出結果。

這題一開始的bfs我想到了,但是好像非常裸,直接就tle了,後來看了某神的題解才知道既需要狀態壓縮還需要反向搜尋。(ps:狀態壓縮想到了,反向沒想到。)    

對於儲存狀態我弄得是個很裸的線性表,某神用的強hash,讓我情何以堪啊~這說明自己對hash的理解還不夠深,主要是對於hash的理解還很弱。

另外對於本題的改變開關的操作使用位運算,xor是一種很好的運算。(和1做xor,都相同為0,不相同為1,其實用not也可以)

program vijos1197;

const

maxn=25;

maxzt=3000011;

dx:array [1..4] of -1..1=(0,-1,0,1);

dy:array [1..4] of -1..1=(-1,0,1,0);

type

atp=record

zt,dep:longint;

end;

var start,n,ii,head,tail:longint;

que,dep,h:array [0..maxzt] of longint;

b:array [0..maxn] of longint;

function hash(x:longint):longint;

var tmp,i:longint;

begin

tmp:=x mod maxzt;

i:=tmp;

while (h[i]<>0) and (h[i]<>x) do

begin

inc(i);

if i>=maxzt then i:=i mod maxzt;

end;

if h[i]=0 then h[i]:=x;

exit(i);

end;

procedure predo;

var i,j,k,t,tx,ty:longint;

begin

head:=0;

tail:=1;

que[1]:=(1 shl 25)-1;

dep[hash(que[1])]:=1;

for i:=1 to 5 do

begin

for j:=1 to 5 do

begin

t:=(i-1)*5+j;

b[t]:=b[t]+1 shl (25-t);

for k:=1 to 4 do

begin

tx:=i+dx[k];

ty:=j+dy[k];

if (tx in [1..5]) and (ty in [1..5]) then b[t]:=b[t]+1 shl (25-(tx-1)*5-ty);

end;

end;

end;

end;

procedure make;

var x,i,xx:longint;

begin

while head

Vijos P1197 費解的開關

描述 你玩過 拉燈 遊戲嗎?25盞燈排成乙個5x5的方形。每乙個燈都有乙個開關,遊戲者可以改變它的狀態。每一步,遊戲者可以改變某乙個燈的狀態。遊戲者改變乙個燈的狀態會產生連鎖反應 和這個燈上下左右相鄰的燈也要相應地改變其狀態。我們用數字 1 表示一盞開著的燈,用數字 0 表示關著的燈。下面這種狀態 ...

費解的開關

你玩過 拉燈 遊戲嗎?25盞燈排成乙個5x5的方形。每乙個燈都有乙個開關,遊戲者可以改變它的狀態。每一步,遊戲者可以改變某乙個燈的狀態。遊戲者改變乙個燈的狀態會產生連鎖反應 和這個燈上下左右相鄰的燈也要相應地改變其狀態。我們用數字 1 表示一盞開著的燈,用數字 0 表示關著的燈。下面這種狀態 101...

費解的開關

時間限制 1 sec 記憶體限制 128 mb 提交 狀態 題目描述 你玩過 拉燈 遊戲嗎?25盞燈排成乙個5x5的方形。每乙個燈都有乙個開關,遊戲者可以改變它的狀態。每一步,遊戲者可以改變某乙個燈的狀態。遊戲者改變乙個燈的狀態會產生連鎖反應 和這個燈上下左右相鄰的燈也要相應地改變其狀態。我們用數字...