Description
在经过地球防卫小队的数学家连续多日的工作之后,外星人发的密码终于得以破解。它告诉我们在地球某一处的古老遗迹中,存在有对抗这次灾难的秘密道具。防卫小队立刻派出了一个直升机小分队,迅速感到了这处遗迹。要进入遗迹,需要通过一段迷之阶梯。登上阶梯必须要按照它要求方法,否则就无法登上阶梯。它要求的方法有以下三个限制:
1.如果下一步阶梯的高度只比当前阶梯高1,则可以直接登上。
2.除了第一步阶梯外,都可以从当前阶梯退到前一步阶梯。
3.当你连续退下k后,你可以一次跳上不超过当前阶梯高度2^k的阶梯。比如说你现在位于第j步阶梯,并且是从第j + k步阶梯退下来的。那么你可以跳到高度不超过当前阶梯高度+ 2^k的任何一步阶梯。跳跃这一次只算一次移动。
开始时我们在第1步阶梯。由于时间紧迫,我们需要用最少的移动次数登上迷之阶梯。请你计算出最少的移动步数。
1.如果下一步阶梯的高度只比当前阶梯高1,则可以直接登上。
2.除了第一步阶梯外,都可以从当前阶梯退到前一步阶梯。
3.当你连续退下k后,你可以一次跳上不超过当前阶梯高度2^k的阶梯。比如说你现在位于第j步阶梯,并且是从第j + k步阶梯退下来的。那么你可以跳到高度不超过当前阶梯高度+ 2^k的任何一步阶梯。跳跃这一次只算一次移动。
开始时我们在第1步阶梯。由于时间紧迫,我们需要用最少的移动次数登上迷之阶梯。请你计算出最少的移动步数。
Input
第1行:一个整数N,表示阶梯步数
第2行:N个整数,依次为每层阶梯的高度,保证递增
第2行:N个整数,依次为每层阶梯的高度,保证递增
Output
第1行:一个整数,如果能登上阶梯,输出最小步数,否则输出-1
Sample Input
5
0 1 2 3 6
Sample Output
7Hint
样例解释:从0到3再返回到0再跳到6
【数据范围】
对于50%的数据:1<=N<=20;
对于100%的数据:1<=N<=200;
每步阶梯高度不超过2^31-1
对于50%的数据:1<=N<=20;
对于100%的数据:1<=N<=200;
每步阶梯高度不超过2^31-1
这题一个经典的麻烦我们的地方在于那个直接往上走一步
实质上仔细想想会发现其实如果我不后退本就可以上升1个高度
然后就等同于2了
然后设f[i]为到第i个台阶的最少步数,接着我们就可以枚举从哪个地方跳下来和跳了多少步
然后就可以直接dp了
code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int a[10003]; 6 int f[300]; 7 int main() { 8 int n; 9 cin>>n; 10 for(int i=1; i<=n; i++)cin>>a[i]; 11 memset(f,0x3f3f3f3f,sizeof f); 12 f[1]=0; 13 for(int i=1; i<=n; i++) { 14 for(int j=1;j<i;j++){ 15 for(int k=0;k<=min(j-1,31);k++){ 16 if(a[i]<=a[j-k]+(1<<k))f[i]=min(f[i],f[j]+k+1); 17 } 18 } 19 } 20 cout<<(f[n]==0x3f3f3f3f?-1:f[n]); 21 return 0; 22 }
转换一下我们如果枚举从那个地方直接跳2^k也是可行的
code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int a[10003]; 6 int f[300]; 7 int main() { 8 int n; 9 cin>>n; 10 for(int i=1; i<=n; i++)cin>>a[i]; 11 memset(f,0x3f3f3f3f,sizeof f); 12 f[1]=0; 13 for(int i=1; i<=n; i++) { 14 for(int j=1;j<i;j++){ 15 for(int k=0;k<i-j;k++){ 16 if(a[j]+(1<<k)>=a[i])f[i]=min(f[i],f[j+k]+k+1); 17 } 18 } 19 } 20 cout<<(f[n]==0x3f3f3f3f?-1:f[n]); 21 return 0; 22 }
还有一种官方的奇葩神仙分层图做法
code:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 typedef long long LL; 5 const LL INF=0x7fffffff/2; 6 LL d[1000005]={0},vst[1000005]={0},lap[2005]={0},n,h[1000005]={0},cnt=0,q[1000005]={0}; 7 struct front_star{int ne,to,v;}a[2500005]; 8 void Addedge(LL x,LL y,LL v) 9 { a[++cnt].to=y;a[cnt].ne=h[x];a[cnt].v=v;h[x]=cnt;} 10 void SPFA(LL u,LL n) 11 { LL i,j,k,L=0,R=1; 12 for(i=1;i<=n;i++)d[i]=INF;d[u]=0; 13 q[1]=u;vst[u]=1; 14 while(L!=R) 15 {L=(L+1)%400005; 16 i=q[L];vst[i]=0; 17 for(k=h[i];k;k=a[k].ne) 18 {j=a[k].to; 19 if(d[j]>d[i]+a[k].v) 20 {d[j]=d[i]+a[k].v; 21 if(!vst[j]) 22 {R=(R+1)%400005;q[R]=j;vst[j]=1;} 23 } 24 } 25 } 26 } 27 int main() 28 { LL i,j,k,p,D; 29 scanf("%lld%lld",&n,&lap[1]); 30 for(i=2;i<=n;i++) 31 {scanf("%d",&lap[i]); 32 if(lap[i]-lap[i-1]==1) 33 for(j=1;j<=n;j++){Addedge((i-1)+(j-1)*n,i,1);} 34 } 35 for(k=1;k<=min(n-1,32LL);k++) 36 {D=(1<<k); 37 for(i=1;i<=n-k;i++) 38 for(j=i+1;j<=n;j++) 39 {if(lap[j]-lap[i]<=D){Addedge(i+k*n,j,1);} 40 else break; 41 } 42 } 43 for(k=33;k<=n;k++) 44 for(i=1;i<=n-k;i++)Addedge(i+k*n,n,1); 45 for(k=1;k<=n-1;k++)for(i=2;i<=n;i++)Addedge(i+(k-1)*n,(i-1)+k*n,1); 46 SPFA(1,n*n); 47 if(d[n]==INF)printf("-1"); 48 else printf("%lld",d[n]); 49 return 0; 50 }
over