洛谷【P1135】奇怪的电梯 解题报告
【传送门】:http://www.luogu.org/problem/show?pid=1135
---------------------------------------------------题目----------------------------------------------------------
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第i层楼(1<=i<=N)上有一个数字Ki(0<=Ki<=N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3 3 1 2 5代表了Ki(K1=3,K2=3,……),从一楼开始。在一楼,按“上”可以到4楼,按“下”是不起作用的,因为没有-2楼。那么,从A楼到B楼至少要按几次按钮呢?
输入输出格式
输入格式:
输入文件共有二行,第一行为三个用空格隔开的正整数,表示N,A,B(1≤N≤200, 1≤A,B≤N),第二行为N个用空格隔开的正整数,表示Ki。
输出格式:
输出文件仅一行,即最少按键次数,若无法到达,则输出-1。
输入输出样例
输入样例#1:
LIFT.IN 5 1 5 3 3 1 2 5
输出样例#1:
LIFT.OUT 3
-------------------------------------------------解题过程--------------------------------------------------------
刚开始写的BFS 拿了80分,错了两个测试点,虽然那个PIN好像有点多余,但还是懒得删QAQ,
//初始代码(BFS版) var head,tail:longint; //对头对尾指针 temp:longint; i,n,a,b,sum:longint; num:array[1..200] of longint; f:array[0..201] of record //记录类型,data用于记录队列里的数,pin用于记录已经走了几次 data:longint; pin:shortint; end; boo:array[1..200] of boolean; //------------------------------------------------- procedure printf(uuu:longint); //输出过程 begin writeln(f[uuu].pin); halt; end; //------------------------------------------------- begin readln(n,a,b); for i:= 1 to n do read(num[i]); //输出过程 if a=b then begin //如果起点等于终点就输出0 writeln(0); halt; end; sum:=n; //sum用于记录剩余可走的层数 head:=0; tail:=1; fillchar(boo,sizeof(boo),true); //初始化 f[1].data:=a; f[1].pin:=0; boo[1]:=false; dec(sum); //错误就在这一行 //BFS开始-------------------------------------------------------------------- while head<tail do begin inc(head); temp:=f[head].data+num[f[head].data]; //往上走 if (temp>=1) and (temp<=n) and (boo[temp]) then begin if sum=0 then begin writeln(-1); halt; end; //这个有点鸡肋,不过懒得删 inc(tail); f[tail].data:=temp; f[tail].pin:=f[head].pin+1; boo[temp]:=false; dec(sum); if temp=b then printf(tail); //到达指定楼层就输出 end; temp:=f[head].data-num[f[head].data]; //往下走 if (temp>=1) and (temp<=n) and (boo[temp]) then begin //同上 if sum=0 then begin writeln(-1); halt; end; inc(tail); f[tail].data:=temp; f[tail].pin:=f[head].pin+1; boo[temp]:=false; dec(sum); if temp=b then printf(tail); end; end; //BFS结束-------------------------------------------------------------------- writeln(-1); //当BFS后发现没办法到达输出 -1 end.
两个错的测试点,一个是因为我用了shortint(退shortint报平安~),还有一个是因为弄错了初始化的时候给boo布尔数组的赋值下标(详见第27行)
正确的BFS版本如下:
//正确代码(BFS版) var head,tail:longint; //对头对尾指针 temp:longint; i,n,a,b,sum:longint; num:array[1..200] of longint; f:array[0..201] of record //记录类型,data用于记录队列里的数,pin用于记录已经走了几次 data:longint; pin:integer; //拒绝shortint,从我做起…… end; boo:array[1..200] of boolean; //------------------------------------------------- procedure printf(uuu:longint); //输出过程 begin writeln(f[uuu].pin); halt; end; //------------------------------------------------- begin readln(n,a,b); for i:= 1 to n do read(num[i]); //输出过程 if a=b then begin //如果起点等于终点就输出0 writeln('0'); halt; end; sum:=n; //sum用于记录剩余可走的层数【鸡肋……】 head:=0; tail:=1; fillchar(boo,sizeof(boo),true); f[1].data:=a; f[1].pin:=0; boo[a]:=false; dec(sum); //已更正错误 //BFS开始-------------------------------------------------------------------- while head<tail do begin inc(head); temp:=f[head].data+num[f[head].data]; //往上走 if (temp<=n) and (boo[temp]) then begin if sum=0 then begin writeln('-1'); halt; end; //这个有点鸡肋,不过懒得删 inc(tail); f[tail].data:=temp; f[tail].pin:=f[head].pin+1; boo[temp]:=false; dec(sum); if temp=b then printf(tail); //到达指定楼层就输出 end; temp:=f[head].data-num[f[head].data]; //往下走 if (temp>0) and (boo[temp]) then begin //同上 if sum=0 then begin writeln('-1'); halt; end; inc(tail); f[tail].data:=temp; f[tail].pin:=f[head].pin+1; boo[temp]:=false; dec(sum); if temp=b then printf(tail); end; end; //BFS结束-------------------------------------------------------------------- writeln('-1'); //当BFS后发现没办法到达输出 -1 end.
题目的标签是递推,但我只会用广搜……不过还是勉强AC了
===================================20170209=======================================
qwq猛然发现原来可以用Floyd,数据太水。。。。
我们初始化为maxlongint div 3,自己到自己就是0,读入时把 i 到它可以到的楼层之间的距离赋为1 就可以啦
然后Floyd裸题
1 program lift; 2 uses math; 3 var 4 i,j,k,tmp,t_o,n,a,b:longint; 5 f:array[1..200,1..200] of longint; 6 7 begin 8 readln(n,a,b); 9 for i:= 1 to n do 10 for j:= 1 to n do 11 if i<>j then f[i,j]:=maxlongint div 2; //初始化 12 13 for i:= 1 to n do 14 begin 15 read(tmp); 16 t_o:=i+tmp; 17 if t_o<=n then f[i,t_o]:=1; 18 t_o:=i-tmp; 19 if t_o>0 then f[i,t_o]:=1; 20 end; 21 22 for k:= 1 to n do 23 for i:= 1 to n do 24 for j:= 1 to n do 25 f[i,j]:=min(f[i,j],f[i,k]+f[k,j]); 26 27 if f[a,n]<>maxlongint div 3 then writeln(f[a,n]) 28 else writeln(-1); 29 end.