1. 程式人生 > 實用技巧 >最短路

最短路

升降梯上

記憶體限制: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層至少需要多長時間?

輸入格式

第一行兩個正整數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≤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; }
View Code