P1052 过河
题意:给出桥的长度,给出石头个数;给出所有石头的位置
背景:有一只不喜欢跳石头的青蛙想要跳尽量少的石头跳到桥对岸 (注:是尽量不跳石头,而不是一定得跳石头)
一开始做这道题的时候,就是以为一定得跳石头才能过,然后以为题意出错(因为数据范围不允许这样跳)
后来才知道原来是什么地方都可以跳
思路:题意范围达到1e9;所以直接dp会超时;
但是,我们可以通过改石头位置来改总长度以此优化复杂度;
题目给出石头个数只有100个,青蛙的跳跃范围是(1,10)
假设有两个石头一个坐标是1,一个是100,那么这两石头之间,有很多不会跳到石头的但是必须跳到的点
所以我们可以将这部分省略,因为这段区间不影响答案
那么怎么省略掉呢,自然是按最大的跳跃距离来跳离这段没有石头的点
于是我们可以直接将这段距离去掉,用数学化的语句来表达就是: (a[i]-a[i-1])%t+t;
最后+t是有原因的,因为不加的话,青蛙距离下一个点的位置就是一个小于t的距离
然后这位置可能导致往前一定跳到石头(如果不在这个位置可能就不跳到石头)
所以我们多加一段t的距离去dp,这样就可以保证得到最优答案;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int inf=0x3f3f3f3f; 4 const int maxn=2e4+10; 5 int dp[maxn]; 6 int stone[maxn]; 7 int a[maxn]; 8 int main() 9 { 10 int len; 11 scanf("%d",&len); 12 int s,t,n; 13 scanf("%d%d%d",&s,&t,&n); 14 a[0]=0; 15 for(int i=1;i<=n;i++){ 16 scanf("%d",&a[i]); 17 } 18 a[n+1]=len; 19 sort(a,a+n+2); 20 int base=0; 21 for(int i=1;i<=n+1;i++){ 22 if(a[i]-a[i-1]>t){ 23 base+=(a[i]-a[i-1])%t; 24 } 25 else base+=a[i]-a[i-1]; 26 stone[base]=1; 27 } 28 stone[base]=0;stone[0]=0; 29 memset(dp,inf,sizeof(dp)); 30 dp[0]=0; 31 for(int i=1;i<=base+t-1;i++){ 32 for(int j=s;j<=t;j++){ 33 if(i-j>=0) 34 dp[i]=min(dp[i],dp[i-j]+stone[i]); 35 } 36 } 37 // for(int i=0;i<=base;i++) 38 // printf("%d ",stone[i]); 39 // printf("\n"); 40 // for(int i=1;i<=base;i++) 41 // printf("%d ",dp[i]); 42 // printf("\n"); 43 int ans=0x3f3f3f3f; 44 for(int i=base;i<=base+t-1;i++) 45 ans=min(ans,dp[i]); 46 printf("%d\n",ans); 47 return 0; 48 }