【Py/Java/C++三种语言OD2023C卷真题】20天拿下华为OD笔试之【贪心/脑筋急转弯】2023C-运输时间【欧弟算法】全网注释最详细分类最全的华为OD真题题解

有LeetCode算法/华为OD考试扣扣交流群可加 948025485
可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳 od1336了解算法冲刺训练

题目描述与示例

题目描述

M (1 <= M <= 20)`辆车需要在一条不能超车的单行道到达终点,起点到终点的距离为`N (1 <= N <= 400)

速度快的车追上前车后,只能以前车的速度继续行驶,求最后一车辆到达目的地花费的时间。

注:每辆车固定间隔1小时出发,比如第一辆车0时出发,第二辆车1时出发,依次类推

输入描述

第一行两个数字:M N分别代表车辆数和到终点的距离,以空格分隔。

接下来M行,每行1个数字 S,代表每辆车的速度。0 < S < 30

输出描述

输出:最后一辆车到达目的地花费的时间。

示例

输入

2 11
3
2

输出

5.5

说明

2`辆车,距离`11`,`0`时出发的车速度快,`1`时出发的车慢,达到目的地花费`5.5

解题思路

本题题意虽然容易理解,但是乍一看相当复杂,像小学奥数会学习的那种追及问题。

如果真的去计算车辆之间相遇的时间和位置,那会算得非常痛苦。

概念辨析

需要注意本题存在两个概念需要进行辨析,到达时刻花费时间

到达时刻指的是以某辆车以第0辆车出发为初始时间节点,从0时开始算起的最终到达终点时的时刻。

花费时间指的是在某辆车在路上所花的时间。

在本题的语境下,假设已知某辆车的到达时刻arrived,它的出发时刻i,那么它在路上的花费时间就是arrived-i

本题要求我们计算的内容是,最后一辆车的花费时间

所以如果我们能够算出最后一辆车的到达时刻last_arrived,由于其出发时刻为已知的N-1,那么就可以直接计算其在路上的花费时间last_arrived-(N-1)

所以本题的重点在于如何计算出最后一辆车的到达时刻

两辆车的简单情况

辨析了上述两个概念之后,我们先从简单的情况入手分析本题。

先考虑两辆车的情况,这是最简单的情况。

假设总路程为DA车先出发(0时),速度为speed_AB车后出发(1时),速度为speed_B,考虑两辆车速度的大小关系。若

  • speed_A >= speed_B,即先出发的车是快车,那么晚到的一定是后出发的车,即最后一辆车的到达时刻取决于后出发的慢车,即存在到达时刻为D / speed_B + 1。其中1表示的是晚出发的时间
  • speed_A < speed_B,即后出发的车更快,那么后出发的快车既有可能赶上,也有可能赶不上先出发的慢车。若
    • 后出发的快车赶上了先出发的慢车,由于快车的速度会被降为和慢车一样的速度,之后两车会同时行驶直至终点,最终后车的到达时刻和前车的到达时刻一致,即存在到达时刻为D / speed_A
    • 后出发的快车没赶上先出发的慢车,即晚到的是后出发的慢车,这种情况其实和speed_A >= speed_B是一样的,即最后一辆车的到达时刻是D / speed_B + 1

那么我们是否需要真的去判断两辆车的速度大小关系,以及计算它们会否追及呢?

答案是不需要

可以看到,在只有两辆车的情况时,后车的到达时刻要么是D / speed_B + 1,要么是D / speed_A

在三个参数Dspeed_Aspeed_B已知的情况下,其到达时刻为上述两个算式中的较大值,即

last_arrived = max(D/speed_A, D/speed_B+1)

那么后车(两辆车中的最后一辆车)在路上的花费时间就是到达时刻last_arrived减去出发时刻1,即

ans = last_arrived - 1

多辆车的复杂情况

将两辆车的简单情况推广到多辆车的复杂情况。

已知第i辆车(索引从0开始)的速度为speed_i,出发时间为i时。

假设路上不存在任何其他车辆,单辆车的到达时刻D / speed_i + i

由于所有车辆的出发时间和速度是独立的,不管怎么相遇、变速,最后一辆车到达终点的时间,实际上也取决于所有车中到达时刻最晚的那辆车

假设所有车辆的速度依次储存在数组speeds中,那么最后一辆车的到达时刻应该为

last_arrived = max(D / speed + i for speed in speeds)

最后一辆车在在路上的花费时间就是到达时刻last_arrived减去出发时刻N-1,即

ans = last_arrived - (N-1)

这就规避了中间过程的复杂计算,而是通过数学逻辑推理,直接贪心地得到最后到达的车的时间。

浮点数输出的讨论

很显然,答案可能出现除不尽的小数,即需要输出浮点数。

但本题并没有明确地告知需要保留几位小数,一般而言直接输出默认值即可。

OJ系统的判题机,会自动计算输出答案和标准答案之间的误差,一般误差在10^-4内就算正确。

代码

Python

# 题目:【贪心】2023C-运输时间
# 分值:200
# 作者:闭着眼睛学数理化
# 算法:贪心,脑筋急转弯
# 代码看不懂的地方,请直接在群上提问


# 输入车辆数目N,起点到终点的距离D
N, D = map(int, input().split())
# 构建speeds数组,speeds[i]表示第i时出发的车的速度
speeds = list()
for _ in range(N):
    speeds.append(int(input()))

# 计算最后一辆车的到达时刻
last_arrived = max(D / speed + i for i, speed in enumerate(speeds))
# 计算最后一辆车在路上行驶的花费时间输出
ans = last_arrived-(N-1)
print(ans)

Java

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 输入车辆数目 N 和 起点到终点的距离 D
        int N = scanner.nextInt();
        int D = scanner.nextInt();

        // 构建 speeds 数组,speeds[i] 表示第 i 时出发的车的速度
        int[] speeds = new int[N];
        for (int i = 0; i < N; i++) {
            speeds[i] = scanner.nextInt();
        }

        // 计算最后一辆车的到达时刻
        double lastArrived = Double.MIN_VALUE;
        for (int i = 0; i < N; i++) {
            double time = (double) D / speeds[i] + i;
            if (time > lastArrived) {
                lastArrived = time;
            }
        }

        // 计算最后一辆车在路上行驶的花费时间并输出
        double ans = lastArrived - (N - 1);
        System.out.println(ans);
    }
}

C++

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int N, D;
    cin >> N >> D;

    // 构建 speeds 数组,speeds[i] 表示第 i 时出发的车的速度
    vector<int> speeds(N);
    for (int i = 0; i < N; i++) {
        cin >> speeds[i];
    }

    // 计算最后一辆车的到达时刻
    double lastArrived = -1;
    for (int i = 0; i < N; i++) {
        double time = static_cast<double>(D) / speeds[i] + i;
        lastArrived = max(lastArrived, time);
    }

    // 计算最后一辆车在路上行驶的花费时间并输出
    double ans = lastArrived - (N - 1);
    cout << ans << endl;

    return 0;
}

时空复杂度

时间复杂度:O(N)。单次循环所花费的时间

空间复杂度:O(1)。仅需若干常数变量


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务300+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

  • 25
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值