zoukankan      html  css  js  c++  java
  • [tyvj2032]升降梯上<dp&spfa>

    题目背景

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

    题目描述

    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。

    输入输出样例

    输入样例#1:
    6 3
    -1 0 2
    输出样例#1:
    19

    说明

    对于30% 的数据,满足1≤N≤ 10; 2≤M≤ 5。

    对于100% 的数据,满足1≤N≤1000; 2 ≤ M ≤20;-N < C1 <C2 < …… < CM < N。

    样例解释

    手柄从第二个槽扳到第三个槽(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 秒。

    这套题考的是图论专题,欧教说这题是spfa。。。。对于这个我有点懵????

    SPFA????????

    好吧说实话我并没有看出来,也不知道怎么去建边建点。。我是用dp做的这道题

    事后同学也说是spfa。。。我。。。。

    好吧我是萌新我不知道大佬们的spfa是咋做的

    我来讲我的dp做法吧

    dp[i][j]表示在第i层的时候在第j槽。。。。

    这个应该不能理解,这个定义同时也可以理解成,在i层的时候,上一次停留是在i-a[j]层

    然后我们在转移状态的时候只需要枚举一下在第i-a[j]层的时候的手柄停留在哪个槽,比如枚举是在第k个槽

    那么在从i-a[j]层到i层需要花费的时间是abs(k-j)+abs(a[j])*2

    ok这样就可以得出状态转移方程式了

    dp[i][j]=min(  dp[i][j]  ,  { dp[ i -a[j] ][ k ] + abs( k - j ) + abs ( a[j] ) * 2 }(1<=k<=m) )

    做到这里,大体就完成了。。。但是不知道有没有注意到一个细节,就是i到底应该从n到1循环还是从1到n循环。。。。

    好吧这个不是大问题,关键在于这个上升楼层有负数,即可以下降。。。。意思是无论我们从n到1还是1到n都不能转移完所有状态

    所有这里可以check一下,如果在dp后数组的值有变化就再来一次,直到数组的值不会变化了。。。这里可以用while实现

     1 #include<cstdio>
     2 #include<queue>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 #include<cmath>
     7 #include<cstdlib>
     8 #define maxn 1005
     9 #define maxm 22
    10 using namespace std;
    11 
    12 int n,m,a[maxm],s,ans=0x3f3f3f,f[maxn][maxm];
    13 int cando=1,val[maxn][maxm];
    14 
    15 void change()
    16 {
    17     for(int i=1;i<=n;i++)
    18      for(int j=1;j<=m;j++)
    19       val[i][j]=f[i][j];
    20 }
    21 
    22 void check()
    23 {
    24     for(int i=1;i<=n;i++)
    25      for(int j=1;j<=m;j++)
    26      {
    27          if(val[i][j]!=f[i][j]){
    28              cando=1;return;//有变动 
    29          }
    30      }    
    31     cando=0;//无变动 
    32 }
    33 
    34 int main()
    35 {
    36     memset(f,0x3f3f3f,sizeof(f));
    37     scanf("%d%d",&n,&m);
    38     for(int i=1;i<=m;i++){
    39         scanf("%d",&a[i]);if(a[i]==0)s=i;
    40     }
    41     f[1][s]=0;
    42     for(int i=1;i<=m;i++){if(i!=s)f[1][i]=abs(s-i);}
    43     
    44     while(cando==1){
    45         change();
    46         for(int i=n;i>=1;i--)
    47         {
    48             for(int j=1;j<=m;j++)
    49             {
    50                 if(j!=s){
    51                     int ncnt=i-a[j];
    52                     if(ncnt<1||ncnt>n)continue;
    53                     for(int k=1;k<=m;k++){
    54                         if(k!=s){
    55                             int ntim=abs(k-j)+abs(a[j])*2;
    56                             f[i][j]=min(f[i][j],ntim+f[ncnt][k]);
    57                         }
    58                     }
    59                 }
    60                 if(i==n)ans=min(ans,f[n][j]);
    61             }
    62         }
    63         check();
    64     }
    65 
    66     if(ans==0x3f3f3f)printf("-1");    
    67     else printf("%d",ans);
    68 }
    View Code
  • 相关阅读:
    web前端开发规范
    前端工程构建工具之Yeoman
    javascript编码规范
    IOS和安卓不同浏览器常见bug
    SASS对css的管理
    移动端开发注意事项
    性能调试工具
    前端开发和其他类别工程师配合的那些事!
    前端工程师常见的面试题
    前端性能优化浏览器+服务器篇
  • 原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7619745.html
Copyright © 2011-2022 走看看