【原题】【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.


posted @ 2010-11-12 10:54  liukee  阅读(1610)  评论(0编辑  收藏  举报