[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

 

posted @ 2017-10-02 10:05  Danzel♂  阅读(385)  评论(0编辑  收藏  举报