士兵过河问题

一、题目描述

一支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。

三、示例

输入

5
43
12 13 15 20 50

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

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
输入

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. 问题本质分析
  • 表层问题:在时间上限内找到最多过河的士兵数,并计算其最短耗时;
  • 深层问题:
  1. 人数与耗时的单调性:过河人数越多,最短耗时必然≥更少人数的最短耗时(单调性),因此可通过二分法高效枚举;
  2. 过河耗时的最优解问题:经典多人过河问题的核心是 “让耗时短的士兵多往返划船”,通过固定公式可快速计算指定人数的最短耗时,无需暴力枚举路径;
  3. 最优策略的选择:≥4 人时,两种策略的耗时对比是减少总耗时的关键,避免无效的往返;
  4. 排序的必要性:优先选择耗时短的士兵过河,才能最大化可行人数(耗时短的人参与往返,总耗时更低)。
3. 核心逻辑
  • 排序预处理:将士兵过河耗时升序排序,保证每次尝试的mid人都是耗时最短的(最大化可行人数);
  • 二分查找:利用 “人数越多,最短耗时越高” 的单调性,枚举可能的过河人数mid
  • 耗时计算:对每个mid,调用经典过河问题的最优耗时公式,计算mid人的最短过河时间;
  • 边界调整:根据耗时与上限的关系,调整二分边界,记录满足条件的最大人数及对应耗时。
4. 步骤拆解
  1. 输入预处理

    • 读取士兵数、时间上限、过河耗时数组,对耗时数组升序排序。
  2. 二分查找初始化

    • 初始化二分边界:min=0(最少人数)、max=n(最多人数),初始化结果字符串ans
  3. 二分枚举过河人数

    • 循环条件:min ≤ max
    • 计算中间值mid(当前尝试的过河人数);
    • 截取前mid个耗时最短的士兵,调用getMinCrossRiverTime计算其最短耗时need
    • 边界调整:
    • need > limitmid人不可行,上界左移(max=mid-1);
    • need < limitmid人可行,记录结果,下界右移(min=mid+1);
    • need = limit:记录结果并终止循环。
  4. 最短耗时计算(getMinCrossRiverTime)

    • 剩余人数 = 1:耗时 = 唯一士兵的耗时;
    • 剩余人数 = 2:耗时 = 两人中较长的耗时;
    • 剩余人数 = 3:耗时 = 次短 + 最短 + 最长;
    • 剩余人数≥4:选两种策略的更优耗时,每轮处理 2 人,直到剩余人数 < 4。
  5. 结果返回

    • 输出记录的 “最大人数 最短耗时”。

五、代码实现

import java.util.Arrays; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int t = sc.nextInt(); int[] times = new int[n]; for (int i = 0; i < n; i++) { times[i] = sc.nextInt(); } System.out.println(getResult(n, t, times)); } /** * @param n 士兵数 * @param limit 过河时间上限 * @param times 数组,元素表示每个士兵的过河时长 * @return ”最多存活士兵数” “最短用时” */ public static String getResult(int n, int limit, int[] times) { // 过河时间升序 Arrays.sort(times); // 最少成功过河人数 int min = 0; // 最多成功过河人数 int max = n; // 记录题解 String ans = ""; // 二分法取可能成功的过河人数 while (min <= max) { // mid是过河人数 int mid = (min + max) / 2; // 计算mid个人过河所需的最短时间need int need = getMinCrossRiverTime(mid, Arrays.copyOfRange(times, 0, mid)); // 如果need超过了过河时间上限limit,那么说明能成功过河的人没这么多 if (need > limit) { max = mid - 1; } else if (need < limit) { // 如果need小于过河时间上限limit,那么说明mid个最快的人可以在limit时间内成功过河 ans = mid + " " + need; // 但是可能还可以过更多人 min = mid + 1; } else { // 如果need == limit,那么说明过河人数刚好可以在limit时间内成功过河,此时可以直接返回 ans = mid + " " + need; break; } } return ans; } // 计算将n个人运到河对岸所需要花费的最少时间 public static int getMinCrossRiverTime(int n, int[] t) { int cost = 0; while (n > 0) { if (n == 1) { cost += t[0]; break; } else if (n == 2) { cost += t[1]; break; } else if (n == 3) { cost += t[1] + t[0] + t[2]; break; } else { cost += Math.min(t[n - 1] + t[0] + t[n - 2] + t[0], t[1] + t[0] + t[n - 1] + t[1]); n -= 2; } } return cost; } }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1141611.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

零基础学习Proteus元器件库大全与原理图绘制流程

从零开始掌握Proteus&#xff1a;元器件库怎么用&#xff1f;原理图如何画&#xff1f;你是不是也遇到过这种情况——刚打开Proteus&#xff0c;想做个简单的LED闪烁电路&#xff0c;结果在“Pick Device”窗口里翻来覆去找不到AT89C51&#xff1f;或者好不容易把元件放好了&am…

FreeModbus在STM32CubeIDE环境下的构建教程

FreeModbus STM32CubeIDE&#xff1a;从零构建工业级通信系统的实战指南 你有没有遇到过这样的场景&#xff1f; 项目需要对接PLC&#xff0c;客户只认Modbus协议&#xff1b;手头的MCU资源有限&#xff0c;商业协议栈又贵又臃肿&#xff1b;开源方案看着不错&#xff0c;但…

sbit在51单片机中的应用:手把手教程(从零实现)

从点亮一个LED开始&#xff1a;深入理解51单片机中的sbit精髓你有没有试过用C语言直接控制一个IO口的某一位&#xff0c;却写了一堆位运算代码&#xff0c;结果还出错了&#xff1f;比如&#xff1a;P1 P1 & 0xFE; // 想让P1.0输出低电平……但真的这么直观吗&#xff1f…

pytorch深度学习笔记13

目录 摘要 反向传播代码实现 摘要 本篇文章继续学习尚硅谷深度学习教程&#xff0c;学习内容是反向传播代码实现 反向传播代码实现 在之前手写数字识别案例的基础上&#xff0c;对SGD的计算过程进行优化。核心就是使用误差的反向传播法来计算梯度&#xff0c;而不是使用差分…

emwin抗锯齿功能底层驱动支持

emWin抗锯齿驱动深度实践&#xff1a;从原理到性能优化的完整指南你有没有遇到过这样的情况&#xff1f;在STM32上跑emWin&#xff0c;画个斜线像“楼梯”&#xff0c;小字体边缘毛刺严重&#xff0c;波形图一动起来就抖——明明代码没错&#xff0c;UI却怎么看怎么别扭。问题很…

USB2.0双层板接口布局实战案例(含原理图)

USB2.0双层板接口设计实战&#xff1a;从原理到稳定通信的完整路径你有没有遇到过这样的情况&#xff1f;一个嵌入式项目眼看就要量产&#xff0c;结果USB设备插上电脑后时好时坏——有时候能识别&#xff0c;有时候直接“失联”。日志里全是“枚举失败”“端点未响应”&#x…

为什么具身智能系统需要能“自我闭环”的认知机制

在很多人眼中&#xff0c;所谓“智能系统”&#xff0c;无非是&#xff1a; 看得清楚、算得很快、决策很聪明。只要感知模型足够好&#xff0c;规划算法足够复杂&#xff0c;系统自然就会“表现出智能”。 这种理解&#xff0c;在纯软件系统中或许还能勉强成立&#xff0c;但一…

screen指令结合GDB调试嵌入式程序的场景分析

用screen和 GDB 构建高效的嵌入式调试工作流你有没有过这样的经历&#xff1a;一边盯着串口终端看启动日志&#xff0c;一边在另一个窗口敲 GDB 命令&#xff0c;手忙脚乱地来回切换&#xff0c;结果一不小心关掉了 OpenOCD 那个“不起眼”的后台窗口——于是整个调试环境崩溃&…

STM32CubeMX安装步骤手把手教程(零基础适用)

零基础也能搞定&#xff01;STM32CubeMX安装全攻略&#xff0c;手把手带你避坑起飞 你是不是也曾在准备开始嵌入式开发时&#xff0c;面对“STM32CubeMX怎么装&#xff1f;”这个问题一头雾水&#xff1f;点开官网下载页面&#xff0c;一堆术语扑面而来&#xff1a;JRE、离线包…

51单片机串口通信实验:零基础实现数据收发

51单片机串口通信实战&#xff1a;从点亮“Hello World”到全双工收发你有没有过这样的经历&#xff1f;写好一段代码&#xff0c;烧录进单片机&#xff0c;然后……盯着几个LED灯猜&#xff1a;“它到底运行到哪一步了&#xff1f;”没有反馈的开发&#xff0c;就像在黑暗中走…

【C++藏宝阁】C++入门:命名空间(namespace)详解

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;C藏宝阁 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录&#x1f4da;专栏订阅推荐&#x1f4cb;前言&#xff1a;为什么需要命名空间&#xff1f;一、命名空间的定义二、命…

DevicePairingHandler.dll文件丢失找不到问题 免费下载方法分享

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

揭秘大数据领域 Eureka 的服务发现的缓存更新机制

揭秘大数据领域 Eureka 的服务发现的缓存更新机制 关键词:大数据、Eureka、服务发现、缓存更新机制、微服务 摘要:在大数据和微服务架构盛行的今天,服务发现是保障系统高效运行的关键环节。Eureka 作为 Netflix 开源的服务发现框架,在业界得到了广泛应用。其缓存更新机制对…

零基础学习JLink下载的完整操作流程

从零开始掌握J-Link固件烧录&#xff1a;深入理解调试原理与实战技巧 你是否曾遇到这样的场景&#xff1f; 编译好的程序无法下载到STM32板子上&#xff0c;Keil提示“Cortex-M Debug Error”&#xff1b;或者在产线批量烧录时&#xff0c;每台设备都要手动点击“Program”&a…

Arduino寻迹小车图解说明:电路连接全解析

从零搭建Arduino寻迹小车&#xff1a;电路连接与控制逻辑全拆解你有没有试过看着别人做的智能小车自动沿着黑线跑&#xff0c;心里痒痒也想动手做一个&#xff1f;别急——其实它没那么神秘。今天我们就来手把手拆解一台Arduino寻迹小车的完整实现过程&#xff0c;不讲空话&…

DevicePairingProxy.dll文件丢失找不到问题 免费下载方法分享

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

虚拟机性能优化实战技术文章大纲CPU分配策略:核心数、亲和性设置

虚拟机性能优化实战技术文章大纲虚拟机性能优化概述虚拟机性能优化的定义与重要性常见性能瓶颈与挑战优化目标&#xff1a;资源利用率、响应速度、稳定性硬件资源配置优化CPU分配策略&#xff1a;核心数、亲和性设置内存分配&#xff1a;动态内存管理、大页内存启用磁盘I/O优化…

Arduino IDE环境搭建实战案例(新手必看)

从零开始玩转硬件编程&#xff1a;Arduino IDE 环境搭建实战全记录 你有没有过这样的经历&#xff1f;买了一块 Arduino 开发板&#xff0c;兴致勃勃插上电脑&#xff0c;结果打开 Arduino IDE 却发现“端口灰了”、“上传失败”、“找不到设备”……明明照着教程一步步来&…

曾仕强老师谈婚姻前应该做什么

网址&#xff1a;曾仕强老师谈婚姻前应该做什么

【2025最新】基于SpringBoot+Vue的洗衣店订单管理系统管理系统源码+MyBatis+MySQL

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价。我就是个在校研究生&#xff0c;兼职赚点饭钱贴补生活费&…