楼梯

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≤N10; 2M5。

对于100% 的数据,满足1N1000; 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;
}

 

 

 

转载于:https://www.cnblogs.com/z360/p/6786220.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值