过河

过河 (优化dp)

在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。对于30%的数据,L <= 10000;对于全部的数据,L <= 10^9。

​ L非常的大,那么怎么办呢?我们发现s和t很小,所以如果两个石头的间隔超过一定值,第二个石头后面一定有区域,青蛙能跳到其中的任意一个点。事实证明如果区域大于st,后面的有一部分区域都是没用的,直接把区域变成就行了。然后直接dp。

#include <cstdio>
#include <algorithm>

const int maxn=105, maxl=1e5+10, INF=1e9;
int l, s, t, m, f[maxl];
int stone[maxn], stone2[maxn];

int main(){
    scanf("%d%d%d%d", &l, &s, &t, &m);
    for (int i=1; i<=m; ++i) scanf("%d", &stone[i]);
    std::sort(stone+1, stone+m+1);
    if (s==t){
        int ans=0;
        for (int i=1; i<=m; ++i)
            if (stone[i]%s==0) ++ans;
        printf("%d", ans);
        return 0;
    }
    for (int i=1; i<=m; ++i){
        if (stone[i]-stone[i-1]>100)
            stone2[i]=stone2[i-1]+100;
        else stone2[i]=stone2[i-1]+stone[i]-stone[i-1];
        f[stone2[i]]=1;
    }
    int tmp=0, ans=INF;
    for (int i=1; i<=stone2[m]+t; ++i){
        tmp=f[i]; f[i]=INF;
        for (int j=s; j<=t; ++j){
            if (i-j<0) break;
            f[i]=std::min(f[i], f[i-j]+tmp);
        }
        if (i>=stone2[m]) ans=std::min(ans, f[i]);
    }
    printf("%d
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/MyNameIsPc/p/7721880.html