一、问题描述
1944年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里,迷宫地形复杂,但是幸好麦克得到了迷宫的地形图。
迷宫的外形是一个长方形,其在南北方向被划分为N行,在东西方向被划分为M列,于是整个迷宫被划分为N*M个单元。我们用一个有序数对(单元的行号,单元的列号)来表示单元位置。南北或东西方向相邻的两个单元之间可以互通,或者存在一扇锁着的门,又或者存在一堵不可逾越的墙。迷宫中有一些单元存放着钥匙,并且所有的门被分为P类,打开同一类的门的钥匙相同,打开不同类的门的钥匙不同。
大兵瑞恩被关押在迷宫的东南角,即(N,M)单元里,并已经昏迷。迷宫只有一个入口,在西北角,也就是说,麦克可以直接进入(1,1)单元。另外,麦克从一个单元移动到另一个相邻单元的时间为1,拿取所在单元的钥匙的时间以及用钥匙开门的时间忽略不计。
输入:
第一行是三个整数,依次表示N,M,P的值;
第二行是一个整数K,表示迷宫中门和墙的总个数;
第I+2行(1<=I<=K),有5个整数,依次为Xi1,Yi1,Xi2,Yi2,Gi:
当Gi>=1时,表示(Xi1,Yi1)单元与(Xi2,Yi2)单元之间有一扇第Gi类的门,当Gi=0时,表示(Xi1,Yi1)单元与(Xi2,Yi2)单元之间有一堵不可逾越的墙;
(其中,|Xi1-Xi2|+|Yi1-Yi2|=1,0<=Gi<=P)
第K+3行是一个整数S,表示迷宫中存放的钥匙总数;
第K+3+J行(1<=J<=S),有3个整数,依次为Xi1,Yi1,Qi:表示第J把钥匙存放在(Xi1,Yi1)单元里,并且第J把钥匙是用来开启第Qi类门的。(其中1<=Qi<=P)
注意:输入数据中同一行各相邻整数之间用一个空格分隔。
输出:
输出文件只包含一个整数T,表示麦克营救到大兵瑞恩的最短时间的值,若不存在可行的营救方案则输出-1。
输入输出示例:
输入文件
4 4 9
9
1 2 1 3 2
1 2 2 2 0
2 1 2 2 0
2 1 3 1 0
2 3 3 3 0
2 4 3 4 1
3 2 3 3 0
3 3 4 3 0
4 3 4 4 0
2
2 1 2
4 2 1
输出文件
14
参数设定:
3<=N,M<=15;
1<=P<=10;
-------------------------------------------------------------------------------------------------------------------
第一次看到这题时想复杂了,但后来一看数据规模,就想到了搜索,在元素上记录了附带的钥匙信息,需要用到一点位运算,这样就转化为了常规的迷宫最短路,显然BFS,注意下判重,代码附上:
const
dx:array[1..4] of longint=(0,-1,1,0);
dy:array[1..4] of longint=(-1,0,0,1);
var
n,m:longint;
g:array[1..15,1..15] of record key:longint; wall:array[1..4] of longint; end;
v:array[1..15,1..15,0..1024] of boolean;
top,last:longint;
q:array[0..1024*225] of record state,x,y,dis:longint; end;
procedure swap(a,b:longint);
begin
a:=a xor b; b:=a xor b; a:=a xor b;
end;
procedure init;
var
p,k,xi1,yi1,xi2,yi2,gi,s,qi,i:longint;
begin
assign(input,'rescue.in');
reset(input);
fillchar(g,sizeof(g),0);
readln(n,m,p);
readln(k);
for i:=1 to k do begin
readln(xi1,yi1,xi2,yi2,gi);
if gi=0 then gi:=-1;
if (xi1>xi2)or(yi2>yi1) then begin swap(xi1,xi2); swap(yi1,yi2); end;
if xi1=xi2 then begin
g[xi1,yi1].wall[4]:=gi;
g[xi2,yi2].wall[1]:=gi;
end else begin
g[xi1,yi1].wall[3]:=gi;
g[xi2,yi2].wall[2]:=gi;
end;
end;
readln(s);
for i:=1 to s do begin
readln(xi1,yi1,qi);
g[xi1,yi1].key:=g[xi1,yi1].key or (1 shl(qi-1));
end;
end;
procedure upload(xi,yi,statei,disi:longint);
begin
if v[xi,yi,statei] then exit;
inc(last);
with q[last] do begin
x:=xi;
y:=yi;
state:=statei;
dis:=disi;
end;
v[xi,yi,statei]:=true;
end;
procedure expand(top:longint);
var
k:longint;
begin
with q[top] do
for k:=1 to 4 do
if (x+dx[k]>=1)and(x+dx[k]<=n)and(y+dy[k]>=1)and(y+dy[k]<=m)and(g[x,y].wall[k]<>-1) then begin
if g[x,y].wall[k]=0 then
upload(x+dx[k],y+dy[k],state or g[x+dx[k],y+dy[k]].key,dis+1);
if (g[x,y].wall[k]<>0)and((state shr(g[x,y].wall[k]-1))and 1=1) then
upload(x+dx[k],y+dy[k],state or g[x+dx[k],y+dy[k]].key,dis+1);
end;
end;
procedure solve;
begin
assign(output,'rescue.out');
rewrite(output);
fillchar(v,sizeof(v),false);
top:=0;
last:=0;
upload(1,1,g[1,1].key,0);
while top<last do begin
inc(top);
with q[top] do
if (x=n)and(y=m) then begin
write(dis);
close(output);
halt;
end;
expand(top);
end;
write(-1);
close(output);
end;
begin
init;
solve;
end.