全网最全面的华为OD机试真题汇总,100%原题题库,不需要开会员即可查看全部内容,更多考题请查看真题库。
真题库:https://www.yuque.com/codernav.com/od
题目:士兵过河II
知识点二分查找排序
时间限制:1s 空间限制:256MB 限定语言:不限
题目描述:
一支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)如果士兵下河游泳,则会被湍急水流直接带走,算作死亡。
请帮忙给出一种解决方案,保证存活的士兵最多,且过河用时最短。
输入描述:
第一行: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)两个士兵的同时划船时,如果划速不同则会导致船原地转圈圈;所以为保持两个士兵划速相同,则需要向划的慢的士兵看齐。
2)两个士兵坐船时,重量增加吃水加深,水的阻力增大;同样的力量划船速度会变慢;
3)由于河水湍急大量的力用来抵消水流的阻力,所2)中过河用时不是a[i] * 2,而是a[i] * 10
示例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[5] 过河用时: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
说明:
可以达到或小于60的一种方案:
第一步: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
解题思路:
这道题没有找到满分答案,平均分10分。博主根据例题写了一下,大家多提提问题,看看该怎样改进一下!
如例二:
5
130
50 12 13 15 20
1、先对士兵进行排序:12 13 15 20 50
2、左边士兵先过河:12 13
12<13且13<12*10,所以耗时为13;对岸士兵12 13,让速度快(12)的返程;岸边士兵 12 15 20 50,对岸士兵13;总耗时13+12=25<130,符合要求
3、右边士兵开始过河:20 50
20<50 且 50<20*10,所以耗时为50;对岸士兵13 20 50,让速度快(13)返程;岸边士兵12 13 15,对岸士兵20 50;25+50+13=88<130,符合要求
4、左边士兵开始过河:12 13
12<13且13<12*10,所以耗时为13;对岸士兵12 13 20 50,让速度快(12)的返程;岸边士兵 12 15,对岸士兵13 20 50;总耗时88+13+12=113<130,符合要求
5、右侧士兵开始过河:12 15
12<15 且 15<12*10,所以耗时为15;对岸士兵12 13 15 20 50,岸边没有士兵,过河结束,总耗时:113+15=128<130,符合要求
代码实现:
package com.codernav.demo.hwod.exam;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
/**
* @title 士兵过河II
* @Description 一支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)如果士兵下河游泳,则会被湍急水流直接带走,算作死亡。
* 请帮忙给出一种解决方案,保证存活的士兵最多,且过河用时最短。
* @Author 开发者导航
* @website https://codernav.com
* @date 2023/5/28
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int T = sc.nextInt();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < N; i++) {
list.add(sc.nextInt());
}
boolean isLeft = true; //是否从左侧士兵开始过河
boolean isRight = true; //右侧士兵是否满足过河条件(排序后右侧士兵耗时长)
int time = 0; //过河时间
int count = 0; //过河士兵数量
int returnTime = 0; //最后一人的返程时间
List<Integer> duian = new ArrayList<>(); //对岸的士兵集合
while (list.size() != 0) {
Collections.sort(list); //对士兵进行排序
int a, b; //坐船的两个士兵
if (isLeft) { //左侧士兵开始过河或者右侧士兵无法过河
a = list.get(0); //左侧第一个士兵
b = list.get(1); //左侧第二个士兵
list.remove(0); //过河的士兵需要移除
list.remove(0);
} else {
a = list.get(list.size() - 2); //右侧第一个士兵(倒数第二个士兵)
b = list.get(list.size() - 1); //右侧第二个士兵(倒数第一个士兵)
list.remove(list.size() - 1);
list.remove(list.size() - 1);
}
count += 2;
int tempTime; //当前两个士兵的过河最优时间
if (a > b) {
tempTime = Math.min(a, b * 10); //找出两人划船的最优方案
} else {
tempTime = Math.min(b, a * 10);
}
if (time + tempTime >= T) { //此时时间已经超时
if (isLeft) { //如果是左侧的士兵则表示时间已经不够了(因为右侧士兵的耗时更长)
if (time + tempTime == T) { //时间刚刚好
time += tempTime;
} else {
count--; //时间超了需要将此次过河的人剔除
time -= returnTime; //上一次返程时间也取消了
}
break; //跳出循环,表示之后不能有士兵过河了
} else {
count -= 2; //过河人数还原
isRight = false; //右侧不再满足过河的时间
isLeft = true;
list.add(a); //过河士兵返回岸边
list.add(b);
}
} else {
time += tempTime; //到此刻士兵过河所花的时间和
if (list.size() == 0) { //士兵已经全部过河直接跳出循环
break;
}
duian.add(a); //对岸的士兵集合添加两个已经过河的士兵
duian.add(b);
Collections.sort(duian); //求出对岸滑的最快的士兵,让他返程
returnTime = duian.get(0);
time += returnTime; //最快的士兵返程所花时间也要加上
if (time >= T) { //此时时间已经超时
time -= duian.get(0); //减去返程所花的时间
if (isLeft) {
break; //如果是左侧士兵则表示之后没有士兵能够过河
} else {
time -= tempTime; //右侧士兵则恢复原样,让左侧的士兵再试试
isRight = false; //右侧士兵不能再过河了
isLeft = true;
count -= 2; //过河人数还原
duian.remove(duian.size() - 1); //对岸的士兵返回岸边
duian.remove(duian.size() - 1);
list.add(a);
list.add(b);
}
} else {
list.add(duian.get(0)); //岸边添加返程的士兵
duian.remove(0); //对岸移除返程的士兵
isLeft = !isRight || !isLeft; //如果右侧士兵无法过河则永远从左侧士兵中选
count--; //过河人数减一(因为返程了)
}
}
}
System.out.println(count + " " + time);
}
}

找到一种用DP实现的
public class SoldierCrossRiver {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int t = sc.nextInt();
int[] nums = new int[n];
for (int i = 0; i t) {
return “0 0″;
}
if (n == 1) {
return 1 + ” ” + nums[0];
}
int[] dp = new int[n];
dp[0] = nums[0];
dp[1] = Math.min(10 * nums[0], nums[1]);
if (dp[1] > t) {
return 1 + ” ” + nums[0];
}
for (int i = 2; i t) {
return i + ” ” + dp[i – 1];
}
}
return n + ” ” + dp[n – 1];
}
}
代码更精简了,非常感谢!