B
开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道、一辆停在轨道底部的电梯、和电梯内一杆控制电梯升降的巨大手柄。
Nescafe 之塔一共有N 层,升降梯在每层都有一个停靠点。手柄有M个控制槽,第i 个控制槽旁边标着一个数Ci,满足C1<C2<C3<⋯⋯<CM。如果Ci>0,表示手柄扳动到该槽时,电梯将上升Ci 层;如果Ci<0,表示手柄扳动到该槽时,电梯将下降-Ci 层;并且一定存在一个Ci=0,手柄最初就位于此槽中。注意升降梯只能在1到N 层间移动,因此扳动到使升降梯移动到1 层以下、N 层以上的控制槽是不允许的。
电梯每移动一层,需要花费2 秒钟时间,而手柄从一个控制槽扳到相邻的槽,需要花费1 秒钟时间。探险队员现在在1 层,并且想尽快到达N 层,他们想知道从1 层到N 层至少需要多长时间?
输入格式
第一行两个正整数N、M。
第二行M 个整数C1、C2⋯⋯CM。
输出格式
输出一个整数表示答案,即至少需要多长时间。若不可能到达输出-1。
样例输入
6 3
-1 0 2
样例输出
19
样例解释
手柄从第二个槽扳到第三个槽(0 扳到2),用时1 秒,电梯上升到3层,用时4 秒。
手柄在第三个槽不动,电梯再上升到5 层,用时4 秒。
手柄扳动到第一个槽(2 扳到-1),用时2 秒,电梯下降到4 层,用时2 秒。
手柄扳动到第三个槽(-1 扳倒2),用时2 秒,电梯上升到6 层,用时4 秒。
总用时为(1+4)+4+(2+2)+(2+4)=19 秒。
数据规模及约定
对于30% 的数据,满足1≤N≤10; 2≤M≤ 5。
对于100% 的数据,满足1≤N≤1000; 2 ≤ M ≤20;-N < C1 <C2 < …… < CM < N。
代码
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define inf 1000000000 #define maxn 2000 #define maxm 100 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} return x*f; } int n,m,p,a[maxn],f[maxn][maxm]; int main() { //freopen("b.in","r",stdin); //freopen("b.out","w",stdout); n=read();//读入有层楼 m=read();//读入有几个档位 for(int i=1;i<=m;i++) a[i]=read();//读入各个档位 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) f[i][j]=inf; //f[i][j]表示在第i层时,控制槽在j时所用的最短时间, //预处理为极大值 for(int i=1;i<=m;i++) if(!a[i]) p=i; //记录最初位置,以及是第几个槽 for(int i=1;i<=m;i++) f[1][i]=abs(i-p);//从第一层到第i层的搬动控制槽档位所用的时间 bool flag=1;//记录为更新过f值 while(flag) {//若flag==0说明此时没有更优的情况,结束更新 flag=0;//置为没有被更新 for(int i=n;i>=1;i--) for(int j=1;j<=m;j++){ int k=i-a[j];//用K记录搬动控制槽档位后所在的层数 if(k>n||k<1) continue;//所在层数不能大于n或小于1 for(int l=1;l<=m;l++) if(f[k][l]+abs(l-j)+abs(a[j])*2<f[i][j]) { //如果在第K层时将搬动档位从l搬到j所用的时间, //加上为搬动在第k层控制槽在l前的最短时间在,加上升降梯移动的时间 //小于在第i层控制槽在j时的时间 flag=1; //flag记录为1,说明更新过了; f[i][j]=f[k][l]+abs(l-j)+abs(a[j])*2;//更新一次最小值; } } } int ans=inf;//答案先设置为极大值,寻找最小值 for(int i=1;i<=m;i++)//对于在第n层,控制档位在i档所用的最短时间进行枚举,选取最小值 ans=min(ans,f[n][i]); printf("%d\n",ans>=inf/2?-1:ans);//如果ans的值过大,说明这个情况没有被更新过, //输出-1,反之,输出答案; return 0; }