Vijos 1002(动态规划)

描述

在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。

题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。

对于30%的数据,L <= 10000;
对于全部的数据,L <= 10^9。

格式

输入格式

输入的第一行有一个正整数L(1 <= L <= 10^9),表示独木桥的长度。第二行有三个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中1 <= S <= T <= 10,1 <= M <= 100。第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。

输出格式

输出只包括一个整数,表示青蛙过河最少需要踩到的石子数。

样例1

样例输入1

10
2 3 5
2 3 5 6 7

样例输出1

2


1、首先,要知道石子的位置并不是顺序给出,所以要对石子位置的数组进行排序。

2、接下来,对程序本身进行分析:

(1)首先分析30%的数据:

        青蛙跳到n位置时,踩到的石子数量只与其上一步的石子数和此位置有关。因为青蛙每次跳跃的长度为S-T,所以青蛙调到n时,其踩到的石子数最少为

f(n)=min{f(n-T),f(n-T+1)······f(n-S)}+b(n)

其中,f(n)为位置为n时踩到的石子最小值,b(n)为1时表示此地有石子。

因为有的位置不可能踩到,所以初始化f(n)为-1,f(0)=0。

(2)当L的值达到10^9,我们无法定义如此大的数组表示整个路程的每一个位置,所以要进一步进行优化。

因为L的值可达10^9,而石头的数量最多只有100个,数量相差如此悬殊,所以肯定存在若干石子之间的距离很大。这将导致什么情况呢?我们都知道,在相邻两颗石子之间,各f(n)的值要么为-1,要么值一样,而当距离达到一定程度时,这之后的每一个位置都有可能被踩到,且f(n)值相等。因为1<=S<=T<=10,所以此值为90。

即如果两颗石子之间距离大于90,则距离第一颗石子90之后的每一个位置都有可能被踩到,且f(n)相等。

有一个特例:当S=T时,解题则尤为简单,判断每一个石子是否可以整出S即可。


#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;


int main()
{
    long int L; //桥的长度
    int S,T,M; //步长,石子数量
    long int stone[102]; //石子位置
    int f[10000];  //f(n)
    int b[10000];  //此位置是否有石子
    int MinStone;
    cin>>L;
    cin>>S>>T>>M;
    for(int i=0;i<M;i++)
        cin>>stone[i];
    if(S!=T)
    {
        sort(stone,stone+M);  //对石子位置进行排序
        stone[M]=L;
        //对长度进行优化,删除无用的位置
        if(stone[0]>90)
        {
            long int k=stone[0]-90;
            for(int i=0;i<=M;i++)
                stone[i]-=k;
        }
        for(int i=1;i<=M;i++)
            if(stone[i]-stone[i-1]>90)
            {
                long int k=stone[i]-stone[i-1]-90;
                for(int j=i;j<=M;j++)
                    stone[j]-=k;
            }
        memset(f,-1,sizeof(f));
        memset(b,0,sizeof(b));
        for(int i=0;i<M;i++)
            b[stone[i]]=1;
        f[0]=0;
        for(int i=S;i<stone[M]+T;i++)
        {
            MinStone=101;
            for(int j=i-T;j<=i-S;j++)
                if(j>=0&&f[j]!=-1&&MinStone>f[j])
                    MinStone=f[j];
            if(MinStone!=101)
                f[i]=MinStone+b[i];
        }
        MinStone=101;
        for(int i=stone[M];i<stone[M]+T;i++)
            if(MinStone>f[i]&&f[i]!=-1)
                MinStone=f[i];
    }
    else
    {
        MinStone=0;
        for(int i=0;i<M;i++)
            if(stone[i]%S==0)
                MinStone++;
    }
    cout<<MinStone;
    return 0;
}
参考:https://blog.csdn.net/liuhuiyi/article/details/8202453



猜你喜欢

转载自blog.csdn.net/qq_36713450/article/details/80032752