贪心算法应用:集合划分问题详解
贪心算法与集合划分问题详解
集合划分问题是组合优化中的经典问题,其核心目标是将元素集合划分为若干满足特定条件的子集。本文将深入探讨贪心算法在集合划分中的应用,涵盖算法原理、适用场景、Java实现细节及优化策略。
一、集合划分问题定义
1.1 基础概念
给定一个集合 S = {x₁, x₂, ..., xₙ}
,需要将其划分为 k
个子集 {S₁, S₂, ..., Sₖ}
,满足:
- 完备性:所有子集的并为原集合
- 互斥性:任意两个子集交集为空
- 特定约束:如子集和相等、子集大小相近等
1.2 常见变种问题
- 等和划分:将集合划分为两个子集,使得两者和相等(如LeetCode 416)
- 最小最大子集和:划分至k个子集,使最大子集和最小(如LeetCode 698)
- 平衡划分:使子集元素数量或属性差异最小
- 多维度划分:同时考虑多个属性(如重量+体积)
1.3 应用场景
- 服务器负载均衡
- 分布式文件存储
- 生产线任务调度
- 数据处理分片
二、贪心算法策略设计
2.1 基本贪心策略
核心思想:通过局部最优选择逐步逼近全局最优解
通用步骤:
- 排序预处理:按关键属性(如数值大小)排序
- 分配策略:依次将元素分配到当前最优子集
- 终止条件:所有元素分配完成
2.2 典型分配策略
问题类型 | 排序方式 | 分配策略 |
---|---|---|
等和划分 | 降序排序 | 优先填充大元素 |
最小最大子集和 | 降序排序 | 当前总和最小的子集优先 |
平衡数量划分 | 无需排序 | 轮询分配 |
2.3 正确性分析
- 等和划分:当总和为偶数且无超大元素时有效
- 最小最大和:提供近似解,近似比通常为2
- NP-Hard证明:多数划分问题属于NP-Hard,贪心提供可行近似解
三、等和划分问题详解
3.1 问题定义
给定非空数组 nums
,判断是否能将其划分为两个子集,使得两个子集的和相等。
3.2 贪心算法实现
public class BalancedPartition {// 辅助类:记录子集状态static class Subset {int sum = 0;List<Integer> elements = new ArrayList<>();}public static boolean canPartition(int[] nums) {int total = Arrays.stream(nums).sum();if (total % 2 != 0) return false;int target = total / 2;Arrays.sort(nums); // 升序排序reverse(nums); // 自定义降序Subset[] subsets = new Subset[2];subsets[0] = new Subset();subsets[1] = new Subset();for (int num : nums) {// 选择当前总和较小的子集int idx = (subsets[0].sum <= subsets[1].sum) ? 0 : 1;if (subsets[idx].sum + num > target) {// 无法放入则尝试另一个子集idx = 1 - idx;if (subsets[idx].sum + num > target) return false;}subsets[idx].sum += num;subsets[idx].elements.add(num);}return subsets[0].sum == subsets[1].sum;}private static void reverse(int[] arr) {int left = 0, right = arr.length - 1;while (left < right) {int temp = arr[left];arr[left++] = arr[right];arr[right--] = temp;}}public static void main(String[] args) {int[] nums1 = {1, 5, 11, 5};System.out.println(canPartition(nums1)); // trueint[] nums2 = {1, 2, 3, 5};System.out.println(canPartition(nums2)); // false}
}
3.3 算法分析
- 时间复杂度:O(n log n)(排序耗时)
- 空间复杂度:O(n)(存储子集信息)
- 局限性:无法处理存在单个元素超过总和一半的情况
四、最小最大子集和问题
4.1 问题定义
给定数组 nums
和整数 k
,将其划分为 k
个连续非空子集,使得最大子集和最小。
4.2 贪心策略实现
public class MinMaxSubsetSum {public static int minMaxSum(int[] nums, int k) {Arrays.sort(nums);reverse(nums);PriorityQueue<Integer> minHeap = new PriorityQueue<>();for (int i = 0; i < k; i++) minHeap.offer(0);for (int num : nums) {int curr = minHeap.poll();curr += num;minHeap.offer(curr);}int max = Integer.MIN_VALUE;while (!minHeap.isEmpty()) max = Math.max(max, minHeap.poll());return max;}private static void reverse(int[] arr) {// 同前文实现}public static void main(String[] args) {int[] nums = {7, 2, 5, 10, 8};System.out.println(minMaxSum(nums, 2)); // 输出18([7,2,5]和[10,8])}
}
4.3 关键逻辑解析
- 降序排序:优先处理大元素
- 最小堆维护子集和:每次选择当前和最小的子集
- 近似比证明:该策略结果不超过最优解的2倍
五、多维约束划分问题
5.1 问题描述
考虑元素的多个属性(如重量、体积、价值),需同时满足多个约束条件。
5.2 装箱问题变种
class Item {int weight;int volume;public Item(int w, int v) {weight = w;volume = v;}
}public class MultiDimBinPacking {public static int minBins(Item[] items, int maxWeight, int maxVolume) {Arrays.sort(items, (a, b) -> Integer.compare(b.weight + b.volume, a.weight + a.volume));List<Bin> bins = new ArrayList<>();for (Item item : items) {boolean placed = false;// 尝试放入已有箱子for (Bin bin : bins) {if (bin.canAdd(item, maxWeight, maxVolume)) {bin.addItem(item);placed = true;break;}}// 创建新箱子if (!placed) {Bin newBin = new Bin();newBin.addItem(item);bins.add(newBin);}}return bins.size();}static class Bin {int currentWeight = 0;int currentVolume = 0;boolean canAdd(Item item, int maxW, int maxV) {return currentWeight + item.weight <= maxW && currentVolume + item.volume <= maxV;}void addItem(Item item) {currentWeight += item.weight;currentVolume += item.volume;}}
}
5.3 策略分析
- 复合排序:根据权重和体积的综合指标排序
- 首次适应策略:遍历现有容器尝试放置
- 复杂度:O(n²) 时间复杂度,适用于中小规模数据
六、性能优化技巧
6.1 数据结构优化
使用TreeSet加速查找:
TreeSet<Bin> bins = new TreeSet<>(Comparator.comparingInt((Bin b) -> b.currentWeight).thenComparingInt(b -> b.currentVolume));// 查找可放置的bin
Bin candidate = bins.floor(searchKey);
6.2 并行处理
利用Java Stream API并行化:
Arrays.stream(items).parallel().sorted(comparator).forEach(item -> {// 分配逻辑});
6.3 缓存优化
预处理常用计算:
int[] prefixSum = new int[nums.length + 1];
for (int i=0; i<nums.length; i++) {prefixSum[i+1] = prefixSum[i] + nums[i];
}
七、正确性证明与反例分析
7.1 等和划分反例
输入:[3, 3, 3, 3]
贪心输出:[[3,3], [3,3]]
(正确)
输入:[4, 4, 4, 6]
贪心失败:需要动态规划
7.2 最小最大和证明
- 最大元素必属于某个子集
- 贪心结果
G ≤ 2 * OPT
- 实例:
[9,8,7,6,5,4,3,2,1]
, k=3
贪心解:19,最优解:17
八、测试用例设计
8.1 常规测试
// 等和划分测试
@Test
void testBalancedPartition() {assertTrue(canPartition(new int[]{1,5,11,5}));assertFalse(canPartition(new int[]{1,2,3,5}));
}// 最小最大和测试
@Test
void testMinMaxSum() {assertEquals(18, minMaxSum(new int[]{7,2,5,10,8}, 2));
}
8.2 边界测试
// 单个元素测试
@Test
void testSingleElement() {assertFalse(canPartition(new int[]{5}));
}// 空输入测试
@Test
void testEmptyInput() {assertEquals(0, minMaxSum(new int[]{}, 0));
}
8.3 性能测试
// 生成10^5个元素的大规模测试
int[] bigData = new int[100000];
Arrays.fill(bigData, 1);
long start = System.currentTimeMillis();
assertTrue(canPartition(bigData));
System.out.println("Time cost: " + (System.currentTimeMillis()-start) + "ms");
九、实际应用案例
9.1 云计算资源分配
- 需求:将虚拟机实例分配到物理机,最小化使用主机数量
- 策略:
- 按虚拟机资源需求(CPU+内存)降序排序
- 使用首次适应递减算法分配
9.2 物流装箱优化
- 需求:装车时同时考虑货物重量和体积
- 实现:
public class CargoOptimizer {// 类似多维划分实现 }
9.3 分布式计算
- 场景:将大数据作业分片到计算节点
- 优化:根据节点处理能力动态调整划分策略
十、总结
10.1 算法选择指南
问题类型 | 推荐算法 | 时间复杂度 | 适用场景 |
---|---|---|---|
小规模精确划分 | 动态规划 | O(n*sum) | 元素较少 |
大规模近似划分 | 贪心算法 | O(n log n) | 实时性要求高 |
多约束复杂划分 | 元启发式算法 | - | 复杂工业场景 |
更多资源:
https://www.kdocs.cn/l/cvk0eoGYucWA
本文发表于【纪元A梦】!
相关文章:

贪心算法应用:集合划分问题详解
贪心算法与集合划分问题详解 集合划分问题是组合优化中的经典问题,其核心目标是将元素集合划分为若干满足特定条件的子集。本文将深入探讨贪心算法在集合划分中的应用,涵盖算法原理、适用场景、Java实现细节及优化策略。 一、集合划分问题定义 1.1 基础…...
electron下载文件
const http require(http); const https require(https); const fs require(fs); const { URL } require(url); const path require(path);// 下载文件函数 function downloadFile(url, savePath) {return new Promise((resolve, reject) > {try {console.log(开始下载…...
Neo4j 数据导入:原理、技术、技巧与最佳实践
在构建知识图谱、社交网络分析或复杂关系系统时,高效准确地将数据导入Neo4j图数据库至关重要。本文基于官方文档,深入探讨Neo4j数据导入的核心原理、主流技术、实用技巧及行业最佳实践。 Neo4j的数据导入不仅是技术操作,更是图模型设计的延续。深入理解存储原理、灵活运用C…...

数论~~~
质数 质数Miller-Rabin算法质因子分解质数筛埃氏筛欧拉筛如果只是计数,埃氏筛改进 快速幂乘法快速幂矩阵快速幂1维k阶实战(提醒:最好在mul函数中作乘法时加上(long long)的强制类型转换 ,或者全部数组换成long long&am…...

web第十次课后作业--Mybatis的增删改查
(一)删除操作 功能:根据主键删除数据 SQL 语句 -- 删除id17的数据 delete from emp where id 17;Mybatis 框架让程序员更关注于 SQL 语句 接口方法 Mapper public interface EmpMapper {//Delete("delete from emp where id 17&qu…...

贪心算法应用:集合覆盖问题详解
贪心算法与集合覆盖问题详解 贪心算法在组合优化问题中展现出独特优势,集合覆盖问题(Set Cover Problem)是其中的经典案例。本文将用2万字全面解析贪心算法在集合覆盖/划分中的应用,涵盖算法原理、正确性分析、Java实现、复杂度证…...
BLOB 是用来存“二进制大文件”的字段类型
BLOB 是用来存“二进制大文件”的字段类型,可以存 0 到 65535 字节的数据,常用来存图片、音频、PDF、Word 等“非文本”内容。 BLOB 0-65535 bytes 二进制形式的长文本数据✅ 关键词 1:BLOB 全称:Binary Large Object中文&…...
5.Declare_Query_Checking.ipynb
这个教程 5.Declare_Query_Checking.ipynb 主要讲解了如何使用 DECLARE 查询检查器来分析事件日志中的约束关系。 1. 主要功能 这个教程展示了如何使用 DeclareQueryChecker 来: 发现事件日志中满足特定支持度的约束模式查询不同类型的约束关系分析活动之间的关联…...

【知识点】第7章:文件和数据格式化
文章目录 知识点整理文件概述文件的打开和关闭文件的读操作文件的写操作 练习题填空题选择题 知识点整理 文件概述 文件是一个存储在辅助存储器上的数据序列,可以包含任何数据内容。概念上,文件是数据的集合和抽象,类似地,函…...

NetSuite Bundle - Dashboard Refresh
儿童节快乐! 今朝发一个Bundle,解决一个NetSuite Dashboard的老问题。出于性能上的考虑,NetSuite的Dashboard中的Portlet,只能逐一手工刷新。有人基于浏览器做了插件,可以进行自动刷新。但是在我们做项目部署时&#…...
AI+3D 视觉重塑塑料袋拆垛新范式:迁移科技解锁工业自动化新高度
在工业自动化浪潮席卷全球的当下,仓储物流环节的效率与精准度成为企业降本增效的关键战场。其中,塑料袋拆垛作为高频、高重复性的作业场景,传统人工或机械臂操作面临着诸多挑战。迁移科技,作为行业领先的 3D 工业相机和 3D 视觉系…...

智慧赋能:移动充电桩的能源供给革命与便捷服务升级
在城市化进程加速与新能源汽车普及的双重推动下,移动充电桩正成为能源供给领域的一场革命。传统固定充电设施受限于布局与效率,难以满足用户即时、灵活的充电需求,而移动充电桩通过技术创新与服务升级,打破了时空壁垒,…...
【项目实践】SMBMS(Javaweb版)(三)登出、注册、注销、修改
文章目录 登出、注册、注销、修改登出操作的实现逻辑及方式防止用户登出后可以继续访问修改密码功能实现导入jsp实现Dao层数据接口实现Service层业务接口注册Servlet 注册和注销 用户的方式导入jsp实现Dao层的数据逻辑实现Service逻辑注册Servlet 登出、注册、注销、修改 登出…...
斐波那契数列------矩阵幂法
斐波那契数列 斐波拉楔数是我们在学递归的使用看到的题目,但递归法是比较慢的,后面我们用循环递进来写的,但今天我有遇到了新的方法—— 矩阵幂法(线性代数的知识点)。 矩阵幂法: F11*F10*F2; F20*F11*…...
【Go语言基础【四】】局部变量、全局变量、形式参数
文章目录 一、一句话总结二、作用域分类1. 局部变量(函数内/块内变量)1.1、语法说明1.2、示例 2. 全局变量(包级变量)2.1、语法说明2.2、示例:全局变量的访问 3. 形式参数(函数参数) 三、作用域…...
DeepSeek 赋能车路协同:智能交通的破局与重构
目录 一、引言二、智能交通车路协同系统概述2.1 系统定义与原理2.2 系统构成2.3 发展现状与挑战 三、DeepSeek 技术剖析3.1 DeepSeek 简介3.2 核心技术原理3.2.1 Transformer 架构3.2.2 混合专家架构(MoE)3.2.3 多头潜在注意力(MLA࿰…...
RabbitMQ 的异步化、解耦和流量削峰三大核心机制
RabbitMQ 的异步化、解耦和流量削峰三大核心机制 RabbitMQ 是解决数据库高并发问题的利器,通过异步化、解耦和流量削峰三大核心机制保护数据库。下面从设计思想到具体实现,深入剖析 RabbitMQ 应对高并发的完整方案: 一、数据库高并发核心痛点…...
Ubuntu 25.10 将默认使用 sudo-rs
非盈利组织 Trifecta Tech Foundation 报告,Ubuntu 25.10 将默认使用它开发的 sudo-rs——用内存安全语言 Rust 开发的 sudo 实现。 Ubuntu 25.10 代号 Questing Quokka,预计将于 2025 年 10 月释出,是一个短期支持版本。Sudo-rs 是 Trifect…...
Maven 和 Gradle 依赖管理的详细说明及示例,涵盖核心概念、配置方法、常见问题解决和工具对比。
一、Maven 依赖管理 1. 核心概念 依赖声明:在 pom.xml 中通过 <dependency> 标签定义依赖项,包含 groupId、artifactId、version。仓库:依赖下载的来源,包括中央仓库(Maven Central࿰…...

【Web应用】若依框架:基础篇21二次开发-页面调整
文章目录 ⭐前言⭐一、课程讲解⭐二、怎样选择设计模式?🌟1、寻找合适的对象✨1) ⭐三、怎样使用设计模式?🌟1、寻找合适的对象✨1) ⭐总结 标题详情作者JosieBook头衔CSDN博客专家资格、阿里云社区专家博主、软件设计工程师博客内…...

【 java 基础知识 第一篇 】
目录 1.概念 1.1.java的特定有哪些? 1.2.java有哪些优势哪些劣势? 1.3.java为什么可以跨平台? 1.4JVM,JDK,JRE它们有什么区别? 1.5.编译型语言与解释型语言的区别? 2.数据类型 2.1.long与int类型可以互转吗&…...

CVE-2020-17518源码分析与漏洞复现(Flink 路径遍历)
漏洞概述 漏洞名称:Apache Flink REST API 任意文件上传漏洞 漏洞编号:CVE-2020-17518 CVSS 评分:7.5 影响版本:Apache Flink 1.5.1 - 1.11.2 修复版本:≥ 1.11.3 或 ≥ 1.12.0 漏洞类型:路径遍历导致的任…...

Excel表格批量下载 CyberWin Excel Doenlaoder 智能编程-——玄武芯辰
使用 CyberWin Excel Downloader 进行 Excel 表格及各种文档的批量下载,优势显著。它能大幅节省时间,一次性获取大量所需文档,无需逐个手动下载,提升工作效率。可确保数据完整性与准确性,避免因重复操作产生失误。还便…...

可编辑PPT | 基于大数据中台新能源智能汽车应用解决方案汽车大数据分析与应用解决方案
这份文档是一份关于新能源智能汽车应用解决方案的详细资料,它深入探讨了智能汽车行业的发展趋势,指出汽车正从单纯交通工具转变为网络入口和智能设备,强调了车联网、自动驾驶、智能娱乐等技术的重要性。文档提出了一个基于大数据中台的车企数…...
【统计方法】基础分类器: logistic, knn, svm, lda
均方误差(MSE)理解与分解 在监督学习中,均方误差衡量的是预测值与实际值之间的平均平方差: MSE E [ ( Y − f ^ ( X ) ) 2 ] \text{MSE} \mathbb{E}[(Y - \hat{f}(X))^2] MSEE[(Y−f^(X))2] MSE 可以分解为三部分࿱…...
AtomicInteger原子变量和例题
目录 AtomicInteger源代码加1操作解决ABA问题的AtomicStampedReference 按顺序打印方法 AtomicInteger源代码 // java.util.concurrent.atomic.AtomicIntegerpublic class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVe…...
simulink有无现成模块可以实现将三个分开的输入合并为一个[1*3]的行向量输出?
提问 simulink有无现成模块可以实现将三个分开的输入合并为一个[1*3]的行向量输出? 回答 Simulink 本身没有一个单独的模块能够直接将三个分开的输入合并成一个 [13] 行向量输出,但是可以通过 组合模块实现你要的效果。 ✅ 推荐方式:Mux …...

k8s集群安装坑点汇总
前言 由于使用最新的Rocky9.5,导致kubekey一键安装用不了,退回Rocky8麻烦机器都建好了,决定手动安装k8s,结果手动安装过程中遇到各种坑,这里记录下; k8s安装 k8s具体安装过程可自行搜索,或者deepseek; 也…...
Selenium 和playwright 使用场景优缺点对比
1. 核心对比概览 特性SeleniumPlaywright诞生时间2004年(历史悠久)2020年(微软开发,现代架构)浏览器支持所有主流浏览器(需驱动)Chromium、Firefox、WebKit(内置引擎)执…...

从 Stdio 到 HTTP SSE,在 APIPark 托管 MCP Server
MCP(Model Context Protocol,模型上下文协议) 是一种由 Anthropic 公司于 2024 年 11 月推出的开源通信协议,旨在标准化大型语言模型(LLM)与外部数据源和工具之间的交互。 它通过定义统一的接口和通信规则…...