最短路
升降梯上
内存限制:128 MiB 时间限制:1000 ms 标准输入输出
题目描述:开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道、一辆停在轨道底部的电梯、和电梯内一杆控制电梯升降的巨大手柄。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层至少需要多长时间?
输入格式
输出格式
样例
数据范围与提示
手柄从第二个槽扳到第三个槽(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。
思路:建边,将时间当作边权用spfa求最短路,将二维的点弄成一维
(可以用dp,但因为可以下降,所以有后效性,不能包括所有的状态,必须循环跑dp直到答案不变)
#include<bits/stdc++.h> using namespace std; const int maxn=20000+10,maxm=5e5+10,inf=0x3f3f3f3f; int a[maxn]; struct Edge{ int to,next,w; }e[maxm]; int head[maxm],tot=0; void Insert(int a,int b,int c){ e[++tot].to=b; e[tot].next=head[a]; e[tot].w=c; head[a]=tot; } bool inq[maxn]; int d[maxn]; void spfa(int s){ memset(d,0x3f,sizeof(d)); d[s]=0; queue<int> q; q.push(s); inq[s]=1; while(!q.empty()){ int u=q.front(); q.pop(); inq[u]=0; for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(d[v]>d[u]+e[i].w){ d[v]=d[u]+e[i].w; if(!inq[v]){ q.push(v); inq[v]=1; } } } } } int main(){ int n,m; scanf("%d%d",&n,&m); int s; for(int i=1;i<=m;i++) { scanf("%d",&a[i]); if(a[i]==0) s=i; } for(int i=1;i<=n;i++){ for(int j=1;j<m;j++){ int x=(i-1)*m+j; Insert(x,x+1,1); Insert(x+1,x,1); } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int v=i+a[j]; if(v<1||v>n) continue; int x=(i-1)*m+j; int y=(v-1)*m+j; Insert(x,y,2*abs(a[j])); } } spfa(s);//因为起点一定是第一行第j列,(1-1)×m+s==s int ans=inf; for(int i=1;i<=m;i++){ int x=(n-1)*m+i; ans=min(ans,d[x]); }//枚举最后一行的扳手位置 if(ans!=inf) printf("%d\n",ans); else printf("-1\n"); return 0; }