zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    既可以支持整数四则运算,也可以支持分数四则运算,可定制出题数量的c语言程序
    NABCD需求分析
    求一维循环数组的最大子数组和(二人结对编程)
    返回一个二维整数数组中最大子数组的和(二人结对)
    返回一个整数数组中最大子数组的和。(二人结对编程)
    二柱子2.0编程总结
    随机生成30道小学二年级四则远算题目2.0
    随机生成30道小学二年级四则远算题目
    搜狗输入法的使用感受与评价
    第一次站立会议
  • 原文地址:https://www.cnblogs.com/lmjer/p/9343380.html
Copyright © 2011-2022 走看看