Luogu P1052 过河(dp)
Posted coder-uranus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P1052 过河(dp)相关的知识,希望对你有一定的参考价值。
题意
题目描述
在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:(0,1,dots ,L)(其中(L)是桥的长度)。坐标为(0)的点表示桥的起点,坐标为(L)的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是(S)到(T)之间的任意正整数(包括(S,T))。当青蛙跳到或跳过坐标为(L)的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度(L),青蛙跳跃的距离范围(S,T),桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
输入输出格式
输入格式:
第一行有(1)个正整数(L(1leq Lleq 10^9)),表示独木桥的长度。
第二行有(3)个正整数(S,T,M),分别表示青蛙一次跳跃的最小距离,最大距离及桥上石子的个数,其中(1leq Sleq Tleq 10,1 le M le 100)。
第三行有(M)个不同的正整数分别表示这(M)个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。
输出格式:
一个整数,表示青蛙过河最少需要踩到的石子数。
输入输出样例
输入样例#1:
10
2 3 5
2 3 5 6 7
输出样例#1:
2
说明
对于(30\%)的数据,(Lleq 10000);
对于全部的数据,(Lleq 10^9)。
(2005)提高组第二题
思路
先考虑部分分的做法。我们定义(dp[i])为跳到坐标(i)时所需踩的最少石头数,那么(dp[i])可以从(dp[i-t],dp[i-t+1],dots ,dp[i-s])转移过来。
但是当(Lleq 10^9)时,数组显然已经开不下了,就算空间够,时间上也不能完成。
想象这么一段区间,它以石头开头,以石头结尾,而且它十分的长,我们会发现,这一段区间中的大部分(dp)值相同,因为中间是没有石头踩的。所以我们可以把这么长的一段区间压缩成很少数目的点,然后直接(dp)就好了。
不过还有一个特例:当(s=t)时,不能用上述方法,我们就特判之后数学方法处理就好了。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=50005,B=100;
int l,s,t,m,last,ans=INT_MAX,dp[MAXN],a[105],p[MAXN],hjj[MAXN];
int read()
{
int re=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return re;
}
int main()
{
l=read(),s=read(),t=read(),m=read();
for(int i=1;i<=m;i++) a[i]=read();
if(s==t)
{
ans=0;
for(int i=1;i<=m;i++) if(a[i]%s==0) ans++;
printf("%d",ans);
return 0;
}
a[0]=0,a[m+1]=l,m+=2;
sort(a,a+m);
for(int i=1;i<m;i++)
if(a[i]-a[i-1]<=B) last+=a[i]-a[i-1],hjj[last]=1;
else last+=B,hjj[last]=1;
hjj[last]=0;
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for(int i=0;i<=last;i++)
for(int j=s;j<=t;j++)
dp[i+j]=min(dp[i+j],dp[i]+hjj[i+j]);
for(int i=0;i<=t;i++) ans=min(ans,dp[last+i]);
printf("%d",ans);
return 0;
}
以上是关于Luogu P1052 过河(dp)的主要内容,如果未能解决你的问题,请参考以下文章
P1052 [NOIP2005 提高组] 过河(dp&路径压缩)