百度&必应权4, 日IP8000. 查看详情
自助收录

2023年华为OD机考真题:士兵过河II

算法刷题2年前 (2023)更新 江南白衣
717 2 0
2023年华为OD机考真题:士兵过河II

全网最全面的华为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);
    }
}

 

© 版权声明

相关文章

2 条评论

  • haha123
    haha123 投稿者

    找到一种用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];
    }
    }

    中国陕西西安市 联通
    回复
    • 江南白衣

      代码更精简了,非常感谢!

      中国江苏南京市 移动
      回复