过河(NOIP2005)

纱雾小屋

妖精老师的水晶城堡

你真信了?
算了吧!第一个是洛谷,第二个是vijos

过河(NOIP2005)_第1张图片

过河(NOIP2005)_第2张图片

知识点

离散化

其实这个是很主要的,至于楼下的那一个……没有什么可看的。

动态规划

如楼上所言,这一题中的动态规划很水!

基本思路

对石头坐标排序
离散化并对石头对应位置打标记
动态规划

详细解释

对石头坐标排序

题目没说读入时是有序的,所以我们要先排序,便于离散化。
注意:我们读入是直接保存坐标

离散化并对石头对应位置打标记

为什么要离散化?

因为木桥的长度太大,我们没法用它去建立数组(就是我们dp要用的),所以我们需要离散化

怎么离散化

当相邻的两块石头之间的距离过大时,有些距离是多余的,也就是说我们需要将这一段距离减掉。
那么这个距离有多长呢?
2520
为什么是它?
因为它是1到10这10个数的最小公倍数
我们跳的范围就是1到10的子区间,所以我们任意挑一个跳的距离,就可以一个石子不占的跳过去,并且对后面不会产生影响,所以这就是无用距离,减去即可。
但要注意,如果差距正好是2520的整数倍,那就要少减去一个2520,为了防止两块石头重叠。(感谢ExecutorTassadar指正错误)

打标记

在另一个数组stone[]对应的处理后的坐标位置设置为1,代表有一个石头。

动态规划

我们用f[i]表示到达i位置时,所要踩到的石头的最小数。
那么我们只需要枚举跳的范围,
就得到:
这里写图片描述

这就是状态转移方程。

难度点评

不是很难,如果知道离散化的话!

代码

(感谢ExecutorTassadar指正错误)

#include
using namespace std;
int  minn,maxx,m,l,i,j,f[300000],a[1000],sum,k=0;
bool stone[300000];
int main()
{
    scanf("%d%d%d%d",&l,&minn,&maxx,&m);
    for (i=1;i<=m;++i){
        scanf("%d",&a[i]);
    }
    sort(a+1,a+m+1);
    for (i=1;i<=m;++i){
        if (a[i]-a[i-1]>2520){
            k+=(a[i]-a[i-1])/2520;
            if((a[i]-a[i-1])%2520==0){
            	k--; 
			} 
        }
        stone[a[i]-k*2520]=1; 
    }
    memset(f,0x3f,sizeof(f));
    f[0]=0;
    for (i=1;i<=252000;++i){
        for (j=maxx;j>=minn;--j){
            if (i-j>=0){
                f[i]=min(f[i-j]+stone[i],f[i]);
            }
        }
    }
    printf("%d",f[252000]);
    return 0;
}

你可能感兴趣的:(NOIP题解,洛谷题解,vijos题解,动态规划,离散化,NOIP详细(良心)题解,NOIP考前复习题目整理)