题目
登上阶梯必须要按照它要求的方法,否则就无法登上阶梯。它要求的方法有以下三个限制:
1. 如果下一步阶梯的高度只比当前阶梯高1,则可以直接登上。
2. 除了第一步阶梯外,都可以从当前阶梯退到前一步阶梯。
3. 当你连续退下k后,你可以一次跳上不超过当前阶梯高度2^k的阶梯。比如说你现在位于第j步阶梯,并且是从第j + k步阶梯退下来的。那么你可以跳到高度不超过当前阶梯高度 + 2^k的任何一步阶梯。跳跃这一次只算一次移动。
开始时你在第1步阶梯。由于时间紧迫,我们需要你预先计算出登上迷之阶梯的最少移动次数。
题解
可以用动态规划
有两种情况:
1.这一步阶梯只比上一步阶梯高1,f[i]=f[i-1]+1
2.从第j(1<=j<=i-1)级阶梯退后k(1<=k<=j-1)级阶梯然后跳上这一步阶梯,f[i]=f[j]+1+(j-k)
时间复杂度O(n3)
也可以用搜索+记忆化,注意剪枝
代码
var
w:array[1..200]of longint;
m:array[0..200]of int64;
n,i,j,k:longint;
f:array[0..200]of longint;
begin
assign(input,'ladder.in');
assign(output,'ladder.out');
reset(input);rewrite(output);
readln(n);
fillchar(f,sizeof(f),$7f);
f[1]:=0;
for i:=1 to n do
read(w[i]);
m[0]:=1;
for i:=1 to 31 do
m[i]:=m[i-1]*2;
for i:=32 to n do
m[i]:=m[i-1];
for i:=2 to n do
begin
if (w[i]-w[i-1]=1)and(f[i-1]+1<f[i]) then f[i]:=f[i-1]+1;
for j:=1 to i-1 do
for k:=1 to j-1 do
if (w[i]-w[k]<=m[j-k])and(f[j]+1+j-k<f[i]) then f[i]:=f[j]+1+j-k;
end;
if f[n]<>f[0] then writeln(f[n]) else writeln('-1');
close(input);close(output);
end.