华为OD机试题库《C++》限时优惠 9.9
华为OD机试题库《Python》限时优惠 9.9
华为OD机试题库《JavaScript》限时优惠 9.9
针对刷题难,效率慢,我们提供一对一算法辅导, 针对个人情况定制化的提高计划(全称1V1效率更高)。
看不懂有疑问需要答疑辅导欢迎私VX: code5bug
题目描述
一支N个士兵的军队正在趁夜色逃亡,途中遇到一条湍急的大河。敌军在T的时长后到达河面,没到过对岸的士兵都会被消灭。现在军队只找到了1只小船,这船最多能同时坐上2个士兵。
- 当1个士兵划船过河,用时为 a[i];0 <= i < N
- 当2个士兵坐船同时划船过河时,用时为 max(a[j],a[i]) 两士兵中用时最长的。
- 当2个士兵坐船1个士兵划船时,用时为 a[i]*10;a[i]为划船士兵用时。
- 如果士兵下河游泳,则会被湍急水流直接带走,算作死亡。
请帮忙给出一种解决方案,保证存活的士兵最多,且过河用时最短。
备注
- 两个士兵的同时划船时,如果划速不同则会导致船原地转圈圈;所以为保持两个士兵划速相同,则需要向划的慢的士兵看齐。
- 两个士兵坐船时,重量增加吃水加深,水的阻力增大;同样的力量划船速度会变慢;
- 由于河水湍急大量的力用来抵消水流的阻力,所以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
题解
这道题目属于贪心算法与动态规划的结合问题。我们需要在有限的时间内让尽可能多的士兵过河,同时保证过河的总时间最短。关键在于如何高效地安排士兵的过河顺序和方式,以最小化总时间。
解题思路
- 排序:首先将士兵的过河时间按升序排序,这样我们可以优先处理过河时间较短的士兵,便于后续的贪心策略。
- 动态规划:使用动态规划数组
dp[i]
表示前i+1
个士兵过河的最短时间。我们需要考虑两种主要的过河策略:
- 策略一:最快的回去接最慢的兵。
- 策略二:最慢的两个士兵一起过河, 最快的两个士兵划船回去并返回。
- 时间计算:对于两个士兵一起过河的情况,有两种方式:
- 两个士兵同时划船,时间为两者中的较大值。
- 一个士兵划船,时间为划船士兵的时间乘以10。
- 终止条件:当
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();
})();
希望这个专栏能让您熟练掌握算法, 🎁🎁🎁 。
整理题解不易, 如果有帮助到您,请给点个赞 ❤️ 和收藏 ⭐,让更多的人看到。🙏🙏🙏