10.20T6 DP

Description

  在经过地球防卫小队的数学家连续多日的工作之后,外星人发的密码终于得以破解。它告诉我们在地球某一处的古老遗迹中,存在有对抗这次灾难的秘密道具。防卫小队立刻派出了一个直升机小分队,迅速感到了这处遗迹。要进入遗迹,需要通过一段迷之阶梯。登上阶梯必须要按照它要求方法,否则就无法登上阶梯。它要求的方法有以下三个限制:
  1.如果下一步阶梯的高度只比当前阶梯高1,则可以直接登上。
  2.除了第一步阶梯外,都可以从当前阶梯退到前一步阶梯。
  3.当你连续退下k后,你可以一次跳上不超过当前阶梯高度2^k的阶梯。比如说你现在位于第j步阶梯,并且是从第j + k步阶梯退下来的。那么你可以跳到高度不超过当前阶梯高度+ 2^k的任何一步阶梯。跳跃这一次只算一次移动。
  开始时我们在第1步阶梯。由于时间紧迫,我们需要用最少的移动次数登上迷之阶梯。请你计算出最少的移动步数。

Input

  第1行:一个整数N,表示阶梯步数
  第2行:N个整数,依次为每层阶梯的高度,保证递增

Output

  第1行:一个整数,如果能登上阶梯,输出最小步数,否则输出-1

Sample Input

5
0 1 2 3 6

Sample Output

7

Hint

样例解释:从0到3再返回到0再跳到6

【数据范围】
  对于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

原文地址:https://www.cnblogs.com/saionjisekai/p/9823391.html