tyvj2032(超级源点)
题目背景
开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道、一辆停在轨道底部的电梯、和电梯内一杆控制电梯升降的巨大手柄。
题目描述
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
说明
对于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 秒。
把电梯处于每层,控制器处于哪个控制槽当做状态编号
把可行状态之间连边
最后把m个终止状态连向同一个源点,即建造一个超级源求最短路即可
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; struct my{ int v; int next; int w; }; struct head{ int u,w; bool operator <(const head &rhs)const{ return w>rhs.w; } }; const int maxn=10000+10; const int maxm=1e6+10; const int nil=0x7f7f7f7f; int c[maxn],fa,n,m,adj[maxm],d[maxm]; bool done[maxm]; my bian[2*maxm]; priority_queue<head>Q; void myinsert(int u,int v,int w){ bian[++fa].v=v; bian[fa].next=adj[u]; bian[fa].w=w; adj[u]=fa; } int id(int x,int y){ return (x-1)*m+y; } void dij(int s){ for (int i=1;i<=n*m+1;i++) d[i]=nil; head x; x.u=s; x.w=0; d[s]=0; Q.push(x); while(!Q.empty()){ x=Q.top();Q.pop(); int u=x.u; if(done[u]) continue; done[u]=true; for (int i=adj[u];i;i=bian[i].next){ int v=bian[i].v; int w=bian[i].w; if(d[v]>d[u]+w){ d[v]=d[u]+w; x.u=v; x.w=d[v]; Q.push(x); } } } } int main(){ int top=0; scanf("%d%d",&n,&m); for (int i=1;i<=m;i++){ scanf("%d",&c[i]); if(c[i]==0) top=i; } for (int i=1;i<=n;i++){ for (int j=1;j<=m;j++){ if(j<m) myinsert(id(i,j),id(i,j+1),1); if(j>1) myinsert(id(i,j),id(i,j-1),1);//位于第i层第j个控制器可以连向另一个控制器 if(i+c[j]<=n&&i+c[j]>=1){ myinsert(id(i,j),id(i+c[j],j),abs(c[j]*2));//位于第i层第j个控制器,可以把电梯升至i+c[j]层 } } } for(int i = 1; i <= m; i++) myinsert(id(n, i), n * m + 1, 0);//把m个终止状态连向同一个源点,即建造一个超级源 dij(id(1,top)); if(d[n*m+1]>=nil) printf("-1"); else printf("%d",d[n*m+1]); return 0; }