士兵过河 - 华为OD机试真题(JavaScript 题解)

华为OD机试题库《C++》限时优惠 9.9

华为OD机试题库《Python》限时优惠 9.9

华为OD机试题库《JavaScript》限时优惠 9.9

针对刷题难,效率慢,我们提供一对一算法辅导, 针对个人情况定制化的提高计划(全称1V1效率更高)。

看不懂有疑问需要答疑辅导欢迎私VX: code5bug

华为OD机试真题

题目描述

一支N个士兵的军队正在趁夜色逃亡,途中遇到一条湍急的大河。敌军在T的时长后到达河面,没到过对岸的士兵都会被消灭。现在军队只找到了1只小船,这船最多能同时坐上2个士兵。

  1. 当1个士兵划船过河,用时为 a[i];0 <= i < N
  2. 当2个士兵坐船同时划船过河时,用时为 max(a[j],a[i]) 两士兵中用时最长的。
  3. 当2个士兵坐船1个士兵划船时,用时为 a[i]*10;a[i]为划船士兵用时。
  4. 如果士兵下河游泳,则会被湍急水流直接带走,算作死亡。

请帮忙给出一种解决方案,保证存活的士兵最多,且过河用时最短。

备注

  • 两个士兵的同时划船时,如果划速不同则会导致船原地转圈圈;所以为保持两个士兵划速相同,则需要向划的慢的士兵看齐。
  • 两个士兵坐船时,重量增加吃水加深,水的阻力增大;同样的力量划船速度会变慢;
  • 由于河水湍急大量的力用来抵消水流的阻力,所以2)中过河用时不是a[i] *2,而是a[i] * 10。

输入描述

第一行:N 表示士兵数(0<N<1,000,000)

第二行:T 表示敌军到达时长(0 < T < 100,000,000)

第三行:a[0] a[1] … a[i]… a[N- 1] a[i]表示每个士兵的过河时长。(10 < a[i]< 100; 0<= i< N)

输出描述

第一行:”最多存活士兵数” “最短用时”

示例1

输入:

5
43
12 13 15 20 50

输出:

3 40

说明:

可以达到或小于43的一种方案:
第一步:a[0] a[1] 过河用时:13
第二步:a[0] 返回用时:12
第三步:a[0] a[2] 过河用时:15

示例2

输入:

5
130
50 12 13 15 20

输出:

5 128

说明:

可以达到或小于130的一种方案:
第一步:a[1] a[2] 过河用时:13
第二步:a[1] 返回用时:12
第三步:a[0] a[4] 过河用时:50
第四步:a[2] 返回用时:13
第五步:a[1] a[2] 过河用时:13
第六步:a[1] 返回用时:12
第七步:a[1] a[3] 过河用时:15
所以输出为: 5 128

示例3

输入:

7
171
25 12 13 15 20 35 20

输出:

7 171

说明:

可以达到或小于171的一种方案:
第一步:a[1] a[2] 过桥用时:13
第二步:a[1] 带火把返回用时:12
第三步:a[0] a[5] 过桥用时:35
第四步:a[2] 带火把返回用时:13
第五步:a[1] a[2] 过桥用时:13
第六步:a[1] 带火把返回用时:12
第七步:a[4] a[6] 过桥用时:20
第八步:a[2] 带火把返回用时:13
第九步:a[1] a[3] 过桥用时:15
第十步:a[1] 带火把返回用时:12
第十一步:a[1] a[2] 过桥用时:13
所以输出为:7 171

题解

这道题目属于贪心算法与动态规划的结合问题。我们需要在有限的时间内让尽可能多的士兵过河,同时保证过河的总时间最短。关键在于如何高效地安排士兵的过河顺序和方式,以最小化总时间。

解题思路

  1. 排序:首先将士兵的过河时间按升序排序,这样我们可以优先处理过河时间较短的士兵,便于后续的贪心策略。
  2. 动态规划:使用动态规划数组 dp[i] 表示前 i+1 个士兵过河的最短时间。我们需要考虑两种主要的过河策略:
    • 策略一:最快的回去接最慢的兵。
    • 策略二:最慢的两个士兵一起过河, 最快的两个士兵划船回去并返回。
  3. 时间计算:对于两个士兵一起过河的情况,有两种方式:
    • 两个士兵同时划船,时间为两者中的较大值。
    • 一个士兵划船,时间为划船士兵的时间乘以10。
  4. 终止条件:当 dp[i] 超过敌军到达时间 T 时,停止计算,此时最多存活的士兵数为 i

JavaScript

const rl = require('readline').createInterface({
    input: process.stdin,
    output: process.stdout,
});

var iter = rl[Symbol.asyncIterator]();

const readline = async () => (await iter.next()).value;

// Author: code5bug
(async () => {
    const N = parseInt(await readline());
    const T = parseInt(await readline());
    const a = (await readline()).split(' ').map(Number);
    a.sort();

    if (a[0] > T) {
        // 所有人都到达不了河对面
        console.log(0, 0);
        return;
    } else if (N === 1) {
        // 只能存活 1 个士兵
        console.log(1, a[0]);
        return;
    }

    let minnum_time = function(t1, t2){
        // 当2个士兵坐船同时划船过河时
        let s1 = Math.max(t1, t2);
        // 当2个士兵坐船1个士兵划船时,用时为 a[i]*10;a[i]为划船士兵用时
        let s2 = Math.min(t1, t2) * 10;
        return Math.min(s1, s2);
    }

    // dp[i] 表示 a[0] ~ a[i] 士兵都过河用时最短时间
    const dp = Array(N);
    dp[0] = a[0];
    // 2个士兵同时划船过河: 同时划船时取用时最长的,只有一人划船时取 a[i] * 10
    dp[1] = Math.min(a[1], a[0] * 10);
    let i = 2
    for (; i < N; i++) {
        // 情况一: 最快的回去接最慢的
        // a[0] 划船回去,minnum_time(a[0], a[i]) 划船过河
        let time1 = dp[i - 1] + a[0] + Math.min(a[i], a[0] * 10);

        // 情况二: 最慢的两个士兵一起过河, 最快的两个士兵划船回去并返回
        // a[0] 划船回去,minnum_time(a[i-1], a[i]) 划船过河, a[1]再划船回去 minnum_time(a[0], a[1]) 划船过河
        let time2 = dp[i - 2] + a[0] + minnum_time(a[i], a[i-1]) + a[1] + minnum_time(a[0], a[1]);
        
        dp[i] = Math.min(time1, time2);

        // 后面的士兵更慢,更不能T时间内过河
        if(dp[i] > T) break;
    }
    console.log(i, dp[i-1]);

    rl.close();
})();

希望这个专栏能让您熟练掌握算法, 🎁🎁🎁 。

整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。🙏🙏🙏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

什码情况

你的鼓励就是我最大的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值