「Poetize9」升降梯上(tyvj2032)(最短路)

开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道、一辆停在轨道底部的电梯、和电梯内一杆控制电梯升降的巨大手柄。
Nescafe之塔一共有N层,升降梯在每层都有一个停靠点。手柄有M个控制槽,第i个控制槽旁边标着一个数Ci,满足 C1<C2<C3<<CM C 1 < C 2 < C 3 < … … < C M 。如果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。

提示
手柄从第二个槽扳到第三个槽(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<C3<<CM<N C 1 < C 2 < C 3 < … … < C M < N

样例数据
输入样例 #1
6 3
-1 0 2
输出样例 #1
19

这题比较有意思哈。乍看之下的确有最短路的感觉,但是感觉有不太一样,因为发现即使到达一个点以后手柄的状态也可能会不一样,那么就点和手柄的位置合起来组合成一个点来做就好啦,也就是说,一个点有两个信息来确定的,那么总点数就是 nm n m ,边数小于 nm n m ,用spfa或者那个什么斯塔拉算法都可以嘛。跑一下就好了,图都不用建,不过re了好多次。
这里我用那个什么斯特拉算法,因为感觉写的不多,所以熟悉一下。
代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;

public class Main
{   
    static int dis[][]=new int[20][1005];
    static boolean vis[][]=new boolean[20][1005];
    static int solve()
    {
        PriorityQueue<Node> que=new PriorityQueue<Node>(11,new Comparator<Node>()
                {

                    @Override
                    public int compare(Node o1, Node o2) {
                        // TODO Auto-generated method stub
                        return o1.d-o2.d;
                    }

                });
        for(int i=0;i<m;i++)
        {
            Arrays.fill(dis[i], Integer.MAX_VALUE);
            Arrays.fill(vis[i], false);
        }
        dis[now][1]=0;
        que.add(new Node(1,now,0));
        while(!que.isEmpty())
        {
            Node temp=que.poll();
            //System.out.println("haha");
            int u=temp.to;
            int cur=temp.cur;
            if(vis[cur][u])
                continue;
            vis[cur][u]=true;
            for(int i=0;i<m;i++)
            {
                int to=u+d[i];
                if(to<1||to>n)
                    continue;
                int cost=Math.abs(i-cur)+2*Math.abs(d[i]);
                if(dis[i][to]>temp.d+cost)
                {
                    dis[i][to]=temp.d+cost;
                    que.add(new Node(to,i,dis[i][to]));
                }
            }
        }
        int ans=Integer.MAX_VALUE;
        for(int i=0;i<m;i++)
            ans=Math.min(ans, dis[i][n]);
        if(ans==Integer.MAX_VALUE)
            return -1;
        return ans;
    }
    static int n,m,now;
    static int d[]=new int[20];
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        for(int i=0;i<m;i++)
        {
            d[i]=sc.nextInt();
            if(d[i]==0)
                now=i;
        }
        System.out.println(solve());
    }
}
class Node
{
    int to,cur,d;
    Node(int _to,int _cur,int _d)
    {
        to=_to;
        cur=_cur;
        d=_d;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值