第十四届蓝桥杯省赛JavaB组试题E【蜗牛】个人题解Dijkstra堆优化

                                                                                 

                                              第十四届蓝桥杯省赛JavaB组试题E【蜗牛】个人题解 Dijkstra堆优化          


文章目录

  • 前言
  • 题目描述
  • 解题思路
  • Code分析
  • Code实现
  • 结语


前言

小伙伴们大家好,好久没更新文章了,最近一直在准备蓝桥杯。为什么我要先发这道题的题解呢?不是因为我当时做出来了,而是因为我当时大意了没做出来。这道题我应该直接秒的,说多了都是泪…唉,一言难尽。话不多说,先看解析吧!

题目描述

第十四届蓝桥杯省赛JavaB组试题E【蜗牛】个人题解Dijkstra堆优化_第1张图片

第十四届蓝桥杯省赛JavaB组试题E【蜗牛】个人题解Dijkstra堆优化_第2张图片
第十四届蓝桥杯省赛JavaB组试题E【蜗牛】个人题解Dijkstra堆优化_第3张图片

没看懂题意?看到“传送门”“魔法蜗牛”怕了吗,哈哈哈哈哈哈哈哈哈! 来,老哥我手把手教你用魔法打败魔法。咱们先来捋捋题目到底是啥意思,看个图↓
第十四届蓝桥杯省赛JavaB组试题E【蜗牛】个人题解Dijkstra堆优化_第4张图片

解题思路

图中方框代表传送门,箭头线代表可走的路径,注意,这些路线都是有方向的。我们可以把所有的位置看作是一个一个的站点,题意就变为了从原点出发,到终点的最短时间,而这个时间就等同于我们最短路径问题的距离。(还是不清楚怎么走的同学,可以配合着我的图画,看看在图片最后的坐标走向是怎么样的。

这道题的难点之一在于如何存储杆子上传送门的位置,通过思考我们可以得知,杆子的位置与杆子的横坐标有关,与传送门的纵坐标有关,我当时太笨了,用了一个类去存,结果在写链式前向星的时候人傻了… 正确的做法是y = idx(杆子的横坐标)+ N(最大站点数目) + ai(传送门的高度) ,这样可以保证传送门的位置是唯一确定的,如果不加N,有可能会与后面的杆子位置重复。

站点位置存好了,那边呢?一共就这么几种边:①水平边,水平边很好办,枚举前n-1个杆子的位置,距离(时间)就是横坐标相减,建立起来就好。②竖直边,传送门与地面的距离,这个刚才说了,注意一点,他们的距离不是直接写高度,上去和下来的速度是不一样的,于是我们有:

static double levelTime = 1.0, downTime = 1.0 / 1.3, upTime = 1.0 / 0.7;

levelTime 表示水平的单位时间,downTime 表示下落的单位时间,upTime 表示爬上杆子的单位时间。③传送门的边,这个边很特殊,因为是瞬移,所以权值为0。


怎么样,是不是可以秒了?我当时也这么觉得,但是我很菜,做这个题的时候已经没多少时间了,真的很慌,没想到怎么存杆子上的位置,他真的,我哭死!!!省一应该没了… 不甘心归不甘心,题解还是要发的!我们来看代码怎么写

Code分析

我们不妨先看看用例范围:1e5?标准的dijkstra堆优化链式前向星建图时间复杂度是O(n logn),稳的!那么边的数目是多少呢?dis[]数组开多大呢?我们从刚才是这个地方“y = idx(杆子的横坐标)+ N(最大站点数目) + ai(传送门的高度)”以及题目的样例范围可以得出,我们给他开3倍大小的N就足够,边呢?应该是这么多:N(水平)+2N(竖直来回)+N(传送门) = 4N,管他呢,反正才N最大才1e5,老哥我待会儿直接直接开十倍。然后就是输出那里,这里用printf来控制一下输出就行,详情看代码。

Code实现

import java.io.*;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 *
 * @Auther: LiangXinRui
 * @Date: 2023/4/8 17:33
 * @Description: 
 * 输入
 * 3
 * 1 10 11
 * 1 1
 * 2 1
 * 输出
 * 4.2
 */

public class Main {
    final static int N = (int) (1e5 + 10), M = 10 * N;
    static int n, total;
    static double levelTime = 1.0, downTime = 1.0 / 1.3, upTime = 1.0 / 0.7;
    static double[] dis = new double[3 * N];//每个杆子到原点的最短距离
    static int[] idx = new int[N];//存每个杆子的横坐标
    static int[] head = new int[M], ends = new int[M], next = new int[M];
    static double[] weights = new double[M];
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    static void add(int start, int end, double weight) {
        ends[total] = end;
        weights[total] = weight;
        next[total] = head[start];
        head[start] = total++;
    }

    public static void main(String[] args) {
        n = nextInt();
        Arrays.fill(head, -1);
        for (int i = 0; i < n; i++) idx[i] = nextInt();
        //存水平的边,上下的边,传送门的边,纵坐标用横坐标+n+ai来表示
        //添加水平边
        add(0, idx[0], levelTime);
        for (int i = 0; i < n - 1; i++) {
            add(idx[i], idx[i + 1], levelTime * (idx[i + 1] - idx[i]));
        }
        for (int i = 0; i < n - 1; i++) {//竖直边
            int ai = nextInt();
            int bi = nextInt();
            //传送门的单向边
            add(idx[i] + N + ai, idx[i + 1] + N + bi, 0);
            //第一个传送门与地面的边
            add(idx[i], idx[i] + N + ai, upTime);
            add(idx[i] + N + ai, idx[i], downTime);
            //第二个传送门与地面的边
            add(idx[i + 1], idx[i + 1] + N + bi, upTime);
            add(idx[i + 1] + N + bi, idx[i + 1], downTime);
        }
        dijkstra();
        System.out.printf("%.2f",dis[idx[n - 1]]);
    }

    static void dijkstra() {
        Deque<Integer> queue = new ArrayDeque<>();
        Arrays.fill(dis, Double.MAX_VALUE);
        dis[0] = 0;
        queue.offer(0);
        while (!queue.isEmpty()) {
            Integer hh = queue.poll();
            for (int i = head[hh]; i != -1; i = next[i]) {
                int j = ends[i];
                if (dis[j] > dis[hh] + weights[i]) {
                    dis[j] = dis[hh] + weights[i];
                    queue.offer(j);
                }
            }
        }
    }

    static int nextInt() {
        try {
            in.nextToken();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (int) in.nval;
    }
}

大家觉得今年的题更难一点吗?在评论区`说说自己的看法吧。

第一时间发题解,求安慰求点赞~ 呜呜呜,感谢大家!!!


结语

初学一门技术时,总有些许的疑惑,别怕,它们是我们学习路上的点点繁星,帮助我们不断成长。

文章粗浅,希望对大家有帮助!

你可能感兴趣的:(数据结构与算法,蓝桥杯,蓝桥杯,算法,java,dijkstra)