Решение
Тема: поиск в ширину, двоичное кодирование
Сложность: выше среднего
Текущее состояние комнаты можно представить как целое число из
`N` x
`N` бит, если валун находится в
`(i,j)`-й клетке комнаты, то
`((i-1)*N+j-1)`-й бит в этом числе установлен в 1, иначе – в 0. Для преобразования из позиции в число и обратно можно использовать следующие подпрограммы:
type position=array[1..4,1..4]of char;
function encode(const pos:position):integer;
var i,j,k,p:integer;
begin
p:=0;
k:=1;
for i:=1 to n do
for j:=1 to n do
begin
if pos[i][j]='@' then
p:=p or k;
k:=k*2;
end;
encode:=p;
end;
procedure decode(p:integer; var pos:position);
var i,j,k:integer;
begin
k:=1;
for i:=1 to n do
for j:=1 to n do
begin
if (p and k)<>0 then
pos[i][j]:='@'
else
pos[i][j]:='.';
k:=k*2;
end;
end;
Далее можно воспользоваться алгоритмом поиска в ширину. В массиве
q хранится очередь из позиций, которые нужно обработать,
q1 – индекс первого элемента в очереди,
q2 – индекс первого свободного элемента. В массиве
h записываем количество ходов, которое необходимо, чтобы получить эту позицию из начальной. Если позиция
i еще не была достигнута, в
h[i] храним
`-1`.
const undef=-1;
var q,h:array[0..65535]of integer;
pos:position;
n,p,i,j,st,fn,q1,q2:integer;
...
procedure movestone(i1,j1,i2,j2:integer);
var np:integer;
begin
if (i2<1) or (i2>n) or (j2<1) or (j2>n) then exit;
if pos[i2][j2]<>'.' then exit;
pos[i2][j2]:='@'; {двигаем валун}
pos[i1][j1]:='.';
np:=encode(pos);
if h[np]=undef then {позиция ранее не достигалась }
begin {добавляем ее в очередь}
h[np]:=h[p]+1;
q[q2]:=np;
inc(q2);
end;
pos[i2][j2]:='.'; {двигаем валун обратно}
pos[i1][j1]:='@';
end;
procedure readpos;
var i,j:integer;
begin
for i:=1 to n do
begin
for j:=1 to n do
read(pos[i][j]);
readln;
end;
end;
...
begin
readln(n)
readpos(pos);
st:=encode(pos);
readpos(pos);
fn:=encode(pos);
for i:=0 to 65535 do
h[i]:=undef;
h[st]:=0;
q[0]:=st;
q1:=0;
q2:=1;
while q1<q2 do
begin
p:=q[q1];
inc(q1);
decode(p,pos);
for i:=1 to n do
for j:=1 to n do
if pos[i][j]='@' then
begin {пытаемся сдвинуть валун во всех направлениях}
movestone(i,j,i-1,j);
movestone(i,j,i+1,j);
movestone(i,j,i,j-1);
movestone(i,j,i,j+1);
end;
end;
writeln(h[fn]);
end.