解题报告 逃跑未遂
二.zj之逃跑未遂
众所周知,zj同学曾经被尼玛大哥抓过。话说那是一个下午大课间,zj同学没有做眼保健操就去超市买东西了,可是不小心碰上了尼玛大哥,zj0.01秒的反应时间后,撒腿就往后跑,他的后面是一条柏油马路,马路不是平坦的,是建在钢板上的,钢板又是建在一些地基上的,每一个地基都有一个高度,一块钢板是平行的,是从一个地基铺到另一个地基的(所以中间的地基不能高于此位置的钢板)(可以是上坡,也可以是下坡),但这两个地基之间最多有k-1个地基。问zj从逃跑点(起点)到教学楼(终点)的路中最少用到几个地基。
输入格式
第一行是N和K,2<=N<=5000,1<=K<=N-1。接下来N行,按顺序是地基的高度h,0<=h<=1000 0000 00。
输出格式
一个整数,表示最少地基数,第一个(起点)和最后一个(终点)一定是被用的地基。
样例输入
13 4
0
1
0
2
4
6
8
6
8
8
9
11
12
样例输出
5
后记:
其实zj跑的挺快的,但是你知道最后为什么还是被抓了吗?
尼玛大哥是骑着自行车的!
这个题看似模拟,实则 DP 。
首先应用一下贪心的思想,当斜率尽可能小的时候,能扩展的节点最多。(显然)
所以转移的时候要用斜率比较小的来转移。
然后,就是上代码了(Leve)。
var
n,m,i,j,k:longint;
min:double;
f:array[0..5000] of longint;
a:array[1..5000] of longint;
begin
assign(input,'escape.in');reset(input);
assign(output,'escape.out');rewrite(output);
readln(n,k);
for i:=1 to n do
read(a[i]);
for i:=1 to n do
f[i]:=i;
//初始化
for i:=2 to n do
begin
min:=maxlongint;
for j:=i-1 downto i-k do
if j>0 then
if (a[i]-a[j])/(i-j)<=min then
begin
min:=(a[i]-a[j])/(i-j); //如果这个点的斜率是当前最小的
if f[i]>f[j]+1 then f[i]:=f[j]+1; //就试图转移
end;
end;
writeln(f[n]);
close(input);
close(output);
end.