zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    leetcode131分割回文串
    leetcode315 计算右侧小于当前元素的个数
    Tensorflow写代码流程&反向传播
    vue脚手架的搭建
    Vue 脱坑记
    简历中的工作经历要怎么写?
    如何制作高水平简历?
    window.location.hash的知识点
    前端面试题小集
    前端面试题
  • 原文地址:https://www.cnblogs.com/zzqc/p/7144445.html
Copyright © 2011-2022 走看看