[CTSC99]拯救大兵瑞恩

来源:互联网 发布:西门子s7 300编程软件 编辑:程序博客网 时间:2024/05/16 00:30

  一、问题描述

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.