HDU 4842 距离压缩DP

过河

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 737    Accepted Submission(s): 48


Problem Description
  在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
 
Input
  本题有多组数据。对于每一组数据来说:第一行有一个正整数L(1 <= L <= 109),表示独木桥的长度。第二行有三个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中1 <= S <= T <= 10,1 <= M <= 100。第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。
 
Output
  对于每一组数据,单独输出一行,只包括一个整数,表示青蛙过河最少需要踩到的石子数。(输出的最后没有多余的换行)
 
Sample Input
10 2 3 5 2 3 5 6 7
 
Sample Output
2
 
Source
 
dp方程很好想  dp[i]=MIN{dp[j]+stone[i]|L-T<=j<=L-S}
由于L很大,无论时间还是空间都是不允许的,我们发现M最多只有100且S,T最大就是10
说明在L很大时石子是很稀疏的,在一大段没有石子的路程中很多的dp[i]都是一样的,我们想到能不能把这段距离给压缩。
当S==T时,跳动的位置都是确定好的我们不能盲目的压缩,只需要统计一下是S倍数位置的石子输出即可。
当S!=T时,如果两个石子间隔大于100,我们将其缩为100,至于为什么是100,其实可以更小这取决与ST大小。
由于这一大段距离没有石子,所以大家的最优解在后面的时候就都一样了。。。前面的几个dp[i]计算出来之后,由于跳动距离的限制,
后面的位置都由这几个位置决定,大家都会选择最优解,所以越往后相似率越高当L很大时就一样了后面的,所以不妨在保持可计算的程度下减小L。
为了防止出错把L也往后延伸了100.
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ql(a) memset(a,0,sizeof(a))
int main()
{
    int L,S,T,N,i,j,k=0;
    int a[105],b[105],dp[10500],vis[10500];
    while(cin>>L>>S>>T>>N){
    memset(dp,inf,sizeof(dp));
    int sb=0; ql(vis);
    if(k!=0) cout<<endl;
        for(i=1;i<=N;++i)
        {
        cin>>b[i];
        if(T==S) {
            if(b[i]%S==0) sb++;
        }
        }
        if(sb) {cout<<sb;continue;}
        sort(b+1,b+1+N);
        a[0]=b[0]=0;b[N+1]=L;
        for(i=1;i<=N+1;++i){
            if(b[i]-b[i-1]>100){
                a[i]=a[i-1]+100;
            }
            else a[i]=a[i-1]+(b[i]-b[i-1]);
            if(i!=N+1) vis[a[i]]++;
        }
        if(a[N+1]!=L) L=a[N+1];
        int ans=inf;
        for(i=1,dp[0]=0;i<=L+100;++i){
           for(j=S;j<=T;++j){
            if(i-j>=0)
                 dp[i]=min(dp[i],dp[i-j]);
           }
           if(vis[i]>0) dp[i]+=vis[i];
        }
         for(i=L;i<=L+100;++i) ans=min(ans,dp[i]);
         cout<<dp[L];
         k++;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zzqc/p/7144445.html