洛谷P1052 [NOIP2005 提高组] 过河(dp+离散化)

博客内容讲述了博主在解决洛谷P1052问题时遇到的困难和解决过程。问题要求求解青蛙在给定跳跃范围和河中石子分布下,跳到河对岸的最短路径。博主最初误以为是贪心算法,后来发现青蛙可在水中跳跃,调整思路使用动态规划。通过缩小距离到最大跳跃倍数,博主实现了代码,并给出了完整的解决方案。
摘要由CSDN通过智能技术生成

链接:
https://www.luogu.com.cn/problem/P1052

最终又是几个小时。

这个题刚开始看的时候还没看懂,怎么找案例也找不到 2 个,最后发现他可以青蛙可以在石子下面。

综上这个题好多坑!

题意:

给你一个河的长度L,再给你青蛙能够跳的最大值和最小值,和石子数。最后给你每个石子所对应的距离。让你求出最少经过几个石子能够到达河的那边(青蛙可以在水中)

刚看到这个题的时候还以为就是一个贪心(当时不知道他可以在水中)然后还在抱怨这个最小值用不到啊。但是发现怎么着案例也不会是2啊,然后右读了读题。发现这个题可以在水中。
然后觉得也是好做啊。如果在板上就加1 ,不在的话就不加。
打完之后发现RTL。右看一看发现这里的L可以是10e9。不爆才怪。
然后我以为我的思路出现问题了。又想了想其他的办法。最终无奈题解。然后发现离答案就仅仅差一个离散化。

思路:

我们从这个dp先来考虑,因为找最小的石子,然后我就考虑到达第i个距离需要多少经过最小几个石子。那么dp方程就比较好考虑了。如果在石子上就加1 ,不在的话就不加。

代码如下:

for(int i=1;i<=L;i++)
for(int j=s;j<=t;j++)
if(i>=j)
    {if(f[i])//f[i]代表第i个是有石子的
    dp[i]=min(dp[i],dp[i-j]+1);
    else
        dp[i]=min(dp[i],dp[i-j]);}

dp解决了,我们再来解决缩短距离。
因为1≤S≤T≤10,1≤M≤100,所以L里面啃硬会有很多很大的空隙,这些空隙是可以适当的缩短而不影响他的结果的。那么缩小到啥时候呢,当距离是最大值和最小值的最小公倍数的时候。以后的每一个点可以到达。所以为了好算就把距离缩小定在了s*t上。

解决了这个代码就差不多都解决了这个题
代码奉上:

#include <bits/stdc++.h>
#include<iostream>
using namespace std;
 int read(){int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;}
int n,m,sum=0;
int f[20000],dp[20000],arr[120],brr[120];
//dp[i]代表到达i个数时青蛙的最少的柿子树


int main(){
	std::ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int L;
cin>>L;
int s,t,m;
cin>>s>>t>>m;
for(int i=1;i<=m;i++)
    cin>>arr[i];
    sort(arr+1,arr+m+1);
    int aaaa=0;
    if(s==t)
    {for(int i=1;i<=m;i++)
    if(arr[i]%s==0)
    aaaa++;
cout<<aaaa<<endl;return 0 ;
}
for(int i=1;i<=m;i++)
{
   int d=arr[i]-arr[i-1];
    if(d>=s*t)
   d=s*t;
    brr[i]=brr[i-1]+d;
    f[brr[i]]=1;
    //cout<<brr[i]<<endl;
}
L=brr[m]+s*t;
//cout<<arr[m]<<endl;
for(int i=0;i<=L;i++)
    dp[i]=1000000000;
dp[0]=0;

for(int i=1;i<=L;i++)
{for(int j=s;j<=t;j++)
{
    if(i>=j)
    {if(f[i])
    dp[i]=min(dp[i],dp[i-j]+1);
    else
        dp[i]=min(dp[i],dp[i-j]);
    }
    //cout<<dp[i]<<endl;
} //cout<<dp[i]<<endl;
}
int sum=dp[L];
//cout<<L<<endl;
//cout<<sum<<endl;
for(int i=arr[m]+1;i<=L;i++)
    sum=min(sum,dp[i]);
    cout<<sum<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晨晓翔同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值