算法:DP
分析:这道题的题目内容实在是太XE了,大叔推倒LOLI,千百年不变的真理啊……(原题来自于SPOJ_4197)
我们可以预处理出推倒某只LOLI的左边界和右边界,还要注意有可能推倒的不一定是最边上的LOLI,也可以是中间的某只LOLI,因此还要处理一下。
由此可得转移方程:
f[i]:=min(f[i],f[last[i]-1]+1);
f[i]:=min(f[i],f[left[i]-1]+1);
f[right[i]]:=min(f[right[i]],f[i-1]+1);
分析:这道题的题目内容实在是太XE了,大叔推倒LOLI,千百年不变的真理啊……(原题来自于SPOJ_4197)
我们可以预处理出推倒某只LOLI的左边界和右边界,还要注意有可能推倒的不一定是最边上的LOLI,也可以是中间的某只LOLI,因此还要处理一下。
由此可得转移方程:
f[i]:=min(f[i],f[last[i]-1]+1);
f[i]:=min(f[i],f[left[i]-1]+1);
f[right[i]]:=min(f[right[i]],f[i-1]+1);
注:推倒确实是多米诺形式的。
program push;
const
maxn=100000;
type
atp=record
x,h:longint;
end;
var
n:longint;
a:array [0..maxn] of atp;
last,f,left,right:array [0..maxn] of longint;
procedure init;
var
i:longint;
begin
readln(n);
for i:=1 to n do readln(a[i].x,a[i].h);
end;
function min(x,y:longint):longint;
begin
if x<y then exit(x) else exit(y);
end;
procedure ycl;
var
i,j,max:longint;
begin
left[1]:=1;
right[n]:=n;
for i:=2 to n do
begin
{求能到达的最左范围且能保证这个最左范围一定是连续的。}
if a[i].x-a[i-1].x<=a[i].h then
begin
left[i]:=left[i-1];
j:=left[i]-1;
while (j>0) and (a[i].x-a[j].x<=a[i].h) do
begin
left[i]:=left[j];
j:=left[j]-1;
end;
end
else left[i]:=i;
end;
for i:=n-1 downto 1 do
begin
{求能到达的最右范围且能保证这个最右范围一定是连续的。}
if a[i+1].x-a[i].x<=a[i].h then
begin
right[i]:=right[i+1];
j:=right[i]+1;
while (j<=n) and (a[j].x-a[i].x<=a[i].h) do
begin
right[i]:=right[j];
j:=right[j]+1;
end;
end
else right[i]:=i;
end;
i:=1;
while i<=n do
begin
for j:=i to right[i] do last[j]:=i;
i:=right[i]+1;
end;
end;
procedure main;
var
i:longint;
begin
fillchar(f,sizeof(f),10);
f[0]:=0;
for i:=1 to n do
begin
f[i]:=min(f[i],f[last[i]-1]+1);
f[i]:=min(f[i],f[left[i]-1]+1);
f[right[i]]:=min(f[right[i]],f[i-1]+1);
end;
end;
begin
assign(input,'push.in'); reset(input);
assign(output,'push.out'); rewrite(output);
init;
ycl;
main;
writeln(f[n]);
close(input); close(output);
end.