【原题】【noip 2005 T2】【动态规划】过河(线性动态规划)
问题
在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点: 0 , 1 ,……, L (其中 L 是桥的长度)。坐标为 0 的点表示桥的起点,坐标为 L 的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是 S 到 T 之间的任意正整数(包括 S,T )。当青蛙跳到或跳过坐标为 L 的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度 L ,青蛙跳跃的距离范围 S,T ,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
输入格式 Input Format
输入文件的第一行有一个正整数 L ( 1 <= L <= 10^9 ),表示独木桥的长度。第二行有三个正整数 S , T , M ,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中 1 <= S <= T <= 10 , 1 <= M <= 100 。第三行有 M 个不同的正整数分别表示这 M 个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。
输出格式 Output Format
输出文件只包括一个整数,表示青蛙过河最少需要踩到的石子数。
分析
方程的话,相信所有人都能写出f[i]表示跳到i位置时,踩到的最少的石子数,那么
f[i]=min(f[i-j])+1(i位置是石头)
f[i]=min(f[i,j])(i位置不是石头),其中j枚举当前这一步跳的距离。
根据题目的数据范围,显然这样的算法是过不了的。方程好像也无法再优化,那么我们发现这道题中,桥巨长,石头巨少,所以我们考虑---状态压缩,即如果两块石头间的距离大于100我们就记为100。这样是不影响结果的,至于怎么证明,略……………………
还有几个地方特别的需要我们注意
1、如果青蛙跳的距离是一个定值,那么我们可以特殊处理。
2、题目并未保证石子是有序给出的,所以,为了保险起见,我们要对石子进行升序排列。
反思
方程绝对不等于得分,不但细节要注意,可能的情况,也要考虑到。noip的题绝对不可能白白送分,有的要求,在题目描述里并未出现。但是,会直接影响到得分。这就要求我们多想,多思考,不要急于打代码,打一道题就要做到可提交的程度。
code
var
a:array[0..100000] of 0..1;
f:array[0..100000] of longint;
stone,st:array[0..100] of longint;
l,s,t,m,i,j,ans:longint;
function min(a,b:longint):longint;
begin
if a<b then exit(a);
exit(b);
end;
begin
readln(l);
readln(s,t,m);
for i:=1 to m do
read(stone[i]);
if s=t then
begin
for i:=1 to m do
if stone[i] mod t=0 then inc(ans);
writeln(ans);
halt;
end;
for i:=1 to m-1 do
for j:=i+1 to m do
if stone[i]>stone[j] then
begin
stone[0]:=stone[i];
stone[i]:=stone[j];
stone[j]:=stone[0];
end;
stone[0]:=0;
stone[m+1]:=l;
l:=0;
for i:=1 to m+1 do
if stone[i]-stone[i-1]>=100 then
begin
st[i]:=st[i-1]+100;
a[st[i]]:=1;
l:=l+100;
end
else
begin
st[i]:=st[i-1]+stone[i]-stone[i-1];
a[st[i]]:=1;
l:=l+stone[i]-stone[i-1];
end;
a[0]:=0;
a[st[m+1]]:=0;
filldword(f,sizeof(f)>>2,maxlongint>>1);
f[0]:=0;
for i:=1 to l+t do
for j:=t downto s do
if i-j>=0 then f[i]:=min(f[i],f[i-j]+a[i]);
ans:=maxlongint;
for i:=l to l+t do
ans:=min(ans,f[i]);
writeln(ans);
end.
浙公网安备 33010602011771号