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。

 

输入输出样例

输入样例#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 秒。

 

把电梯处于每层,控制器处于哪个控制槽当做状态编号

把可行状态之间连边

最后把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;
}

 

posted @ 2018-07-20 20:10  lmjer  阅读(351)  评论(0编辑  收藏  举报