链接:
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;
}