【蓝桥】线性DP--最快洗车时间

ops/2025/2/18 16:52:58/

题目描述​

解题思路

完整代码

举例

总结

基于 0/1 背包思想 解决 洗车时间分配问题,本质上是子集和问题【给定一个 正整数数组 nums 和一个目标值 target,判断是否可以从 nums 选择 若干个数(每个数最多选一次),使其和 恰好等于 target

题目描述

 

解题思路

一开始用的使用了排序+贪心的方法:

  • 对洗车时间从大到小排序(先分配长时间的任务)。
  • 优先分配给当前时间较短的那个人(类似负载均衡)。
  • 遍历数组,依次分配,最终返回 max(wash1, wash2)

        但这种思路是错的,求的是局部最优解 ,局部最优不一定导致全局最优,即在每一步都选择当前看起来最好的方案,并不一定能得到最优解

正确方法:设所有洗车时间之和为 total,我们希望 找到一个子集,使得其和 best 尽可能接近 total / 2。这样 max(best, total - best) 就是两人最优的洗车时间

1. 定义状态

dp[j] 表示是否可以从数组 nums 中选取若干个数,使得它们的和为 j

  • dp[j] = true 表示存在一个子集的和恰好等于 j
  • dp[j] = false 表示无法找到这样的子集。

2. 状态转移方程

对于当前遍历的 nums[i]

  • 如果不选 nums[i],那么 dp[j] 由前一轮 dp[j] 继承;
  • 如果选 nums[i],那么 dp[j] 取决于 dp[j - nums[i]] 是否为 true,即如果 j - nums[i] 之前是可行的,那么 j 也是可行的。

状态转移方程:

3. 初始化

  • dp[0] = true(因为总和为 0 的子集是空集,肯定可以达到)。
  • 其他 dp[j] 初始设为 false

4. 遍历顺序

  • 外层循环 遍历 nums[i](每个数只能选一次,必须按顺序遍历)。
  • 内层循环 采用 逆序 for (int j = target; j >= nums[i]; j--),确保 nums[i] 只被选取 一次
  • 最终遍历最终的DP数组,从 target 开始向 0 逆序查找 最大的 i,满足 dp[i] == true

完整代码

#include <bits/stdc++.h>
using namespace std;
const int N = 110; // 设定数组大小
bool dp[N];  // 0/1 背包 DP 数组
int car[N];  // 存储每辆车的洗车时间
int n, target, total; // 变量定义int main() {cin >> n; // 读取车辆数量for (int i = 1; i <= n; i++) {cin >> car[i];total += car[i]; // 计算洗车时间总和}target = total / 2; // 目标是尽量分成两半dp[0] = true; // 初始状态,和为 0 一定是可行的for (int i = 1; i <= n; i++) { // 遍历每辆车for (int j = target; j >= car[i]; j--) { // 逆序遍历dp[j] = dp[j] || dp[j - car[i]];}}int best = 0;// 找到最接近 total/2 的可行解for (int i = target; i >= 0; i--) { if (dp[i]) {best = i;break;}}cout << max(best, total - best); // 计算最短最大时间return 0;
}

举例

n = 4
car = [8, 6, 5, 5]
total = 8 + 6 + 5 + 5 = 24
target = total / 2 = 24 / 2 = 12

初始化dp

dp = [true, false, false, ..., false]  // 长度为 target + 1,即 13

第 1 辆车 (洗车时间 8): 

dp[12] = dp[12] || dp[12 - 8] = false || dp[4] = false
dp[11] = dp[11] || dp[11 - 8] = false || dp[3] = false
dp[10] = dp[10] || dp[10 - 8] = false || dp[2] = false
dp[9] = dp[9] || dp[9 - 8] = false || dp[1] = false
dp[8] = dp[8] || dp[8 - 8] = false || dp[0] = true   // dp[8] = true

第 2 辆车 (洗车时间 6): 

dp[12] = dp[12] || dp[12 - 6] = false || dp[6] = false
dp[11] = dp[11] || dp[11 - 6] = false || dp[5] = false
dp[10] = dp[10] || dp[10 - 6] = false || dp[4] = false
dp[9] = dp[9] || dp[9 - 6] = false || dp[3] = false
dp[8] = dp[8] || dp[8 - 6] = true  || dp[2] = false
dp[7] = dp[7] || dp[7 - 6] = false || dp[1] = false
dp[6] = dp[6] || dp[6 - 6] = false || dp[0] = true   // dp[6] = true

.......

最终

dp = [true, false, false, false, false, true, true, false, true, true, true, true, false]

总结

转换成 0/1 背包问题,利用 动态规划 解决。
dp[j] 表示是否能凑出 j 这个和,递推转移 dp[j] = dp[j] || dp[j - car[i]]
时间复杂度 O(n * sum/2),适用于 sum ≤ 10^4
贪心方法可能失效,而动态规划保证最优解


http://www.ppmy.cn/ops/158568.html

相关文章

Spring Boot 的约定优于配置,你的理解是什么?

约定优于配置"&#xff08;Convention over Configuration&#xff09;是 Spring Boot 的核心设计理念之一。它的核心思想是通过提供一组合理的默认配置&#xff0c;减少开发者需要手动配置的工作量&#xff0c;从而提高开发效率和应用的一致性。以下是对这一理念的详细理…

StableDiffusion学习笔记——1、环境搭建

目录   大家好&#xff0c;我是阿赵。   阿赵我对各种技术都有浓厚的兴趣&#xff0c;对AI相关的技术也不例外。随着AI技术的不断发展&#xff0c;出现了很多不同的AI绘图和视频制作的工具&#xff0c;比如常见的Stable Diffusion和ComfyUI。   现在出现了很多现成可用的…

AI成为基础设施有哪些研究方向:模型的性能、可解释性,算法偏见

AI成为基础设施有哪些研究方向 模型的性能、可解释性和降低训练成本 伦理问题:算法偏见、数据隐私保护、人工智能的权利和责任 数据使用问题:公开数据已经使用完了,未来使用隐私数据(专家) 当AI成为基础设施后,研究方向将更加多元化和深入,涵盖技术创新、应用拓展、…

LabVIEW 用户界面设计基础原则

在设计LabVIEW VI的用户界面时&#xff0c;前面板的外观和布局至关重要。良好的设计不仅提升用户体验&#xff0c;还能提升界面的易用性和可操作性。以下是设计用户界面时的一些关键要点&#xff1a; 1. 前面板设计原则 交互性&#xff1a;组合相关的输入控件和显示控件&#x…

游戏引擎学习第103天

仓库:https://gitee.com/mrxiao_com/2d_game_2 回顾bug 接下来回顾一下这个bug的具体情况。当前是一个调试视图&#xff0c;我们并不是直接在调试视图下工作&#xff0c;而是在进行相关的调试。展示了地图&#xff0c;这里是环境贴图&#xff0c;上面是正在使用的环境贴图&am…

自己部署 DeepSeek 助力 Vue 开发:打造丝滑的时间线(Timeline )

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 自己…

第一章嵌入式系统概论考点03嵌入式系统的分类

第一章常考知识点有: 了解嵌入式系统的特点、分类、发展与应用,熟悉嵌入式系统的逻辑组成。 了解嵌入式处理芯片的主要类型,熟悉SoC的开发流程,理解IP核的重要意义。 熟悉中西文字的编码和数字文本的类型与处理,掌握数字图像的参数、文件格式及其主要应用。 理解计算机…

duckdb导出Excel和导出CSV速度测试

运行duckdb数据库 D:>duckdb v1.2.0 5f5512b827 Enter “.help” for usage hints. Connected to a transient in-memory database. Use “.open FILENAME” to reopen on a persistent database. 生成模拟数据&#xff0c;10个列&#xff0c;100万行数据&#xff1b; --…