ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

升降梯上——玄学dp

2020-07-05 21:04:50  阅读:238  来源: 互联网

标签:升降梯 leq 玄学 手柄 int 电梯 dp


升降梯上

题目描述

开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道、一辆停在轨道底部的电梯、和电梯内一杆控制电梯升降的巨大手柄。

\(Nescafe\) 之塔一共有N层,升降梯在每层都有一个停靠点。手柄有M个控制槽,第i个控制槽旁边标着一个数 \(C_i\),满足 \(C_1<C_2<C_3<……<C_M\)。如果 \(C_i>0\),表示手柄扳动到该槽时,电梯将上升 \(C_i\) 层;如果 \(C_i<0\),表示手柄扳动到该槽时,电梯将下降 \(-C_i\) 层;并且一定存在一个 \(C_i=0\),手柄最初就位于此槽中。注意升降梯只能在 \(1-N\) 层间移动,因此扳动到使升降梯移动到 \(1\) 层以下、\(N\) 层以上的控制槽是不允许的。

电梯每移动一层,需要花费 \(2\) 秒钟时间,而手柄从一个控制槽扳到相邻的槽,需要花费 \(1\) 秒钟时间。探险队员现在在 \(1\) 层,并且想尽快到达 \(N\) 层,他们想知道从 \(1\) 层到 \(N\) 层至少需要多长时间?

输入格式

第一行两个正整数 \(N\)、\(M\)。

第二行M个整数 \(C_1\)、\(C_2……C_M\)。

输出格式

输出一个整数表示答案,即至少需要多长时间。若不可能到达输出 \(-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\leq N\leq 10,2\leq M\leq 5\)。

对于 \(100\%\) 的数据,满足 \(1\leq N\leq 1000,2\leq M\leq 20,-N<C_1<C_2<……<C_M<N\)。

思路

这个题做法很多,本博主只讲其中 \(dp\) 的玄学做法,若想看最短路,\(Dfs\)等做法,出门右转

首先我们可以定义一个 \(dp[i][j]\),表示当手柄在第 \(i\) 的位置时,走到了第 \(j\) 层。

我们上一个状态不能确定到底是在哪个手柄,所以要挨个枚举一遍。

时间加上移动手柄的时间和升降梯移动的时间,去最小值即可。

动态转移方程:

if(i==k){//这个判断加不加都可
      dp[i][j]=min(dp[k][j-c[i]]+abs(c[i])*2,dp[i][j]);
}else{
      dp[i][j]=min(dp[k][j-c[i]]+abs(i-k)+abs(c[i])*2,dp[i][j]);
}

思路很好想,但是实现时会发现仅进行一遍,有些点并没有更新。

所以我们进行多次 \(dp\),发现到第 \(4\) 次时,所有的值都进行了更新,而且不再改变。

若我们在一次 \(dp\) 中,正反都进行一遍,只需 \(3\) 次即可。

若只正向进行,所需的次数就很玄学,保险起见直接 \(20\) 次。

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn=1000+50,INF=0x3f3f3f3f;
int n,m;
int x0;
int c[maxn];
int dp[50][maxn];
int ans=INF;
bool cmp(int a,int b){
      return a>b;
}

int main(){
      memset(dp,0x3f,sizeof(dp));//初始为最大
      scanf("%d%d",&n,&m);
      for(int i=1;i<=m;i++){
            scanf("%d",&c[i]);
	    if(c[i]==0){
                  x0=i;//找到手柄的起始点
            }
      }
      for(int i=1;i<=m;i++){
            dp[i][1]=abs(i-x0);//初始化
      }
      dp[x0][1]=0;//初始化
      for(int s=1;s<=20;s++){//保险20次
            for(int i=1;i<=m;i++){//当前状态
                  for(int j=2;j<=n;j++){//当前层数
                        for(int k=1;k<=m;k++){//上一个状态
                              if(j-c[i]<=0||j-c[i]>n)continue;//若上一个状态越界,直接跳过
                              if(i==k){//可省略判断
                                    dp[i][j]=min(dp[k][j-c[i]]+abs(c[i])*2,dp[i][j]);
                              }else{
                                    dp[i][j]=min(dp[k][j-c[i]]+abs(i-k)+abs(c[i])*2,dp[i][j]);
                              }
                        }
                  }
            }
      }
      for(int i=1;i<=m;i++){
	      ans=min(ans,dp[i][n]);
      }
      if(ans==INF){
	      printf("-1\n");
      }else{
	      printf("%d\n",ans);
      }
      return 0;
}

标签:升降梯,leq,玄学,手柄,int,电梯,dp
来源: https://www.cnblogs.com/Rubyonly233/p/13251790.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有