贪心算法应用:埃及分数问题详解
贪心算法与埃及分数问题详解
埃及分数(Egyptian Fractions)问题是数论中的经典问题,要求将一个真分数表示为互不相同的单位分数之和。本文将用2万字全面解析贪心算法在埃及分数问题中的应用,涵盖数学原理、算法设计、Java实现、优化策略及扩展应用。
一、埃及分数问题定义
1.1 基本概念
- 单位分数:分子为1的正分数(如1/2、1/3)
- 埃及分数表示:任何正有理数可表示为有限个不同单位分数之和
- 数学定理:∀ a/b ∈ (0,1), ∃ 有限序列 {1/k₁, 1/k₂, …, 1/kₙ} 使得 a/b = Σ 1/kᵢ
1.2 问题形式化
输入:两个正整数 a, b(满足 0 < a < b)
输出:一组互不相同的单位分数,使得它们的和等于 a/b
示例:
7/8 = 1/2 + 1/3 + 1/24
2/3 = 1/2 + 1/6
5/6 = 1/2 + 1/3
二、贪心算法策略与数学原理
2.1 贪心选择策略
每次选择满足以下条件的最大单位分数:
- 1/k ≤ 当前剩余分数
- k 是满足条件的最小正整数
数学推导:
对于剩余分数 a’/b’,选择:
k = ceil(b'/a')
然后计算新剩余分数:
a'/b' - 1/k = (a'*k - b') / (b'*k)
2.2 正确性证明
- 终止性:每次操作后分子严格递减
- 新分子:a’’ = a’*k - b’ < a’
- 正确性:通过数学归纳法可证明总能找到解
2.3 算法步骤
- 初始化剩余分数为 a/b
- 循环直到剩余分数为0:
a. 计算当前最大单位分数 1/k
b. 将 1/k 加入结果集
c. 计算剩余分数 = 剩余分数 - 1/k
d. 化简剩余分数 - 返回结果集
三、基础Java实现
3.1 核心代码结构
import java.util.ArrayList;
import java.util.List;public class EgyptianFractions {// 计算最大公约数private static int gcd(int a, int b) {while (b != 0) {int temp = b;b = a % b;a = temp;}return a;}// 分数化简private static int[] reduceFraction(int a, int b) {int common = gcd(a, b);return new int[]{a / common, b / common};}// 贪心算法分解埃及分数public static List<String> getEgyptianFractions(int numerator, int denominator) {List<String> result = new ArrayList<>();while (numerator != 0) {// 计算当前k值int k = (int) Math.ceil((double) denominator / numerator);result.add("1/" + k);// 计算剩余分数: numerator/denominator - 1/kint newNumerator = numerator * k - denominator;int newDenominator = denominator * k;// 化简分数int[] reduced = reduceFraction(newNumerator, newDenominator);numerator = reduced[0];denominator = reduced[1];}return result;}public static void main(String[] args) {List<String> egyptian = getEgyptianFractions(7, 8);System.out.println("7/8 = " + String.join(" + ", egyptian));// 输出: 7/8 = 1/2 + 1/3 + 1/24}
}
3.2 代码解析
- gcd函数:计算最大公约数用于分数化简
- reduceFraction方法:将分数化为最简形式
- 核心循环逻辑:
- 计算当前最大单位分数的分母k
- 更新剩余分数分子分母
- 化简分数防止数值膨胀
3.3 时间复杂度分析
- 最坏情况:O(n)(n为分解步数)
- 每步计算:O(1)
- 实际效率取决于输入分数特性
四、高级实现与优化
4.1 防止整数溢出
使用长整型存储中间结果:
public static List<String> getEgyptianFractionsSafe(int numerator, int denominator) {List<String> result = new ArrayList<>();long num = numerator;long den = denominator;while (num != 0) {long k = (den + num - 1) / num; // 避免浮点计算result.add("1/" + k);long newNum = num * k - den;long newDen = den * k;// 化简long common = gcd(newNum, newDen);num = newNum / common;den = newDen / common;}return result;
}private static long gcd(long a, long b) {while (b != 0) {long temp = b;b = a % b;a = temp;}return a;
}
4.2 迭代代替递归
避免栈溢出风险:
public static List<String> getEgyptianFractionsIterative(int numerator, int denominator) {List<String> result = new ArrayList<>();int[] current = {numerator, denominator};while (current[0] != 0) {int a = current[0];int b = current[1];int k = (int) Math.ceil((double) b / a);result.add("1/" + k);int[] next = {a * k - b, b * k};int gcd = gcd(next[0], next[1]);current[0] = next[0] / gcd;current[1] = next[1] / gcd;}return result;
}
4.3 性能优化技巧
- 预计算加速:缓存常用分数分解
- 并行计算:多线程处理多个分数分解
- 符号处理:扩展支持负数分数
五、数学证明与实例分析
5.1 正确性证明
基例:当a=1时,直接返回1/b
归纳步骤:假设对a’ < a成立,则:
- 选择k = ⌈b/a⌉
- 剩余分数 (ak - b)/(bk) 的分子 a’ = a*k - b < a
- 根据归纳假设,剩余分数可分解
5.2 实例推演
以7/8为例:
步骤1: k = ceil(8/7)=2 → 1/2
剩余: 7/8 - 1/2 = 3/8
步骤2: k = ceil(8/3)=3 → 1/3
剩余: 3/8 - 1/3 = 1/24
步骤3: k=24 → 1/24
剩余: 0 → 终止
结果: 1/2 + 1/3 + 1/24
5.3 算法局限性
- 分解结果可能不是最短的埃及分数表示
示例:5/121 贪心分解需要多步,存在更优解 - 分母可能快速增长导致数值溢出
六、测试用例设计
6.1 基础测试
@Test
void testBasicCases() {// 测试用例1: 7/8List<String> result1 = EgyptianFractions.getEgyptianFractions(7, 8);assertEquals(Arrays.asList("1/2", "1/3", "1/24"), result1);// 测试用例2: 2/3List<String> result2 = EgyptianFractions.getEgyptianFractions(2, 3);assertEquals(Arrays.asList("1/2", "1/6"), result2);
}
6.2 边界测试
@Test
void testEdgeCases() {// 分子为1List<String> result3 = EgyptianFractions.getEgyptianFractions(1, 5);assertEquals(Collections.singletonList("1/5"), result3);// 大分母测试List<String> result4 = EgyptianFractions.getEgyptianFractions(1, 1000);assertEquals(Collections.singletonList("1/1000"), result4);
}
6.3 性能测试
@Test
void testPerformance() {long start = System.currentTimeMillis();EgyptianFractions.getEgyptianFractions(1234, 4321);long duration = System.currentTimeMillis() - start;assertTrue(duration < 100, "Time cost should be less than 100ms");
}
七、扩展应用与变种问题
7.1 最短埃及分数表示
- 属于NP难问题
- 需结合回溯法或动态规划
- 示例:5/121 = 1/25 + 1/757 + 1/763309 + 1/8739601…(贪心法需要更多项)
7.2 现代应用场景
- 密码学:在门限方案中分配秘密份额
- 资源分配:将总资源分解为多个独立配额
- 数学教育:分数运算教学工具
7.3 多分子扩展
处理形如2/5的分解:
2/5 = 1/3 + 1/15 = 1/4 + 1/6 + 1/20
八、与其他算法对比
8.1 贪心算法 vs 回溯法
特性 | 贪心算法 | 回溯法 |
---|---|---|
时间复杂度 | O(n) | 指数级 |
结果质量 | 非最优但快速 | 可得最优解 |
内存消耗 | O(1) | O(n) |
适用场景 | 快速近似解 | 小规模精确解 |
8.2 贪心算法 vs 几何方法
- 几何方法:基于斐波那契-西尔维斯特数列
- 优势:能产生更短的分解
- 缺点:实现复杂度高
九、总结
9.1 改进方向
- 结合启发式搜索优化结果长度
- 开发混合算法(贪心+动态规划)
- 扩展支持分数运算符号处理
更多资源:
https://www.kdocs.cn/l/cvk0eoGYucWA
本文发表于【纪元A梦】!
相关文章:

贪心算法应用:埃及分数问题详解
贪心算法与埃及分数问题详解 埃及分数(Egyptian Fractions)问题是数论中的经典问题,要求将一个真分数表示为互不相同的单位分数之和。本文将用2万字全面解析贪心算法在埃及分数问题中的应用,涵盖数学原理、算法设计、Java实现、优…...

高效集成AI能力:使用开放API打造问答系统,不用训练模型,也能做出懂知识的AI
本文为分享体验感受,非广告。 一、蓝耘平台核心功能与优势 丰富的模型资源库 蓝耘平台提供涵盖自然语言处理、计算机视觉、多模态交互等领域的预训练模型,支持用户直接调用或微调,无需从零开始训练,显著缩短开发周期。 高性能…...

Qt 仪表盘源码分享
Qt 仪表盘源码分享 一、效果展示二、优点三、源码分享四、使用方法 一、效果展示 二、优点 直观性 数据以图表或数字形式展示,一目了然。用户可以快速获取关键信息,无需深入阅读大量文字。 实时性 仪表盘通常支持实时更新,确保数据的时效性。…...

Python数据可视化科技图表绘制系列教程(四)
目录 带基线的棒棒糖图1 带基线的棒棒糖图2 带标记的棒棒糖图 哑铃图1 哑铃图2 包点图1 包点图2 雷达图1 雷达图2 交互式雷达图 【声明】:未经版权人书面许可,任何单位或个人不得以任何形式复制、发行、出租、改编、汇编、传播、展示或利用本博…...
RPM 数据库修复
RPM 数据库修复 1、备份当前数据库(重要!) sudo cp -a /var/lib/rpm /var/lib/rpm.backup此操作保护原始数据,防止修复失败导致数据丢失 2、清除损坏的锁文件 sudo rm -f /var/lib/rpm/__db.*这些锁文件(如 __db.00…...
R语言基础知识总结(超详细整理)
一、R语言简介 R是一种用于统计分析、数据可视化和科学计算的开源编程语言和环境。其语法简洁,内置丰富的统计函数和图形函数,广泛应用于数据科学、机器学习和生物统计等领域。 整体知识点目录: R语言基础知识总结 │ ├─ 安装与配置 │ …...

深入理解系统:UML类图
UML类图 类图(class diagram) 描述系统中的对象类型,以及存在于它们之间的各种静态关系。 正向工程(forward engineering)在编写代码之前画UML图。 逆向工程(reverse engineering)从已有代码建…...
C# 中的 IRecipient
IRecipient<TMessage> 是 .NET 中消息传递机制的重要组成部分,特别是在 MVVM (Model-View-ViewModel) 模式中广泛使用。下面我将详细介绍这一机制及其应用。 基本概念 IRecipient<TMessage> 是 .NET Community Toolkit 和 MVVM Toolkit 中定义的一个接…...
大模型RNN
RNN(循环神经网络)是一种专门处理序列数据的神经网络架构,在自然语言处理(NLP)、语音识别、时间序列分析等领域有广泛应用。其核心作用是捕捉序列中的时序依赖关系,即当前输出不仅取决于当前输入࿰…...
Python环境搭建竞赛技术文章大纲
竞赛背景与意义 介绍Python在数据科学、机器学习等领域的重要性环境搭建对于竞赛项目效率的影响常见竞赛平台对Python环境的特殊要求 基础环境准备 操作系统选择与优化(Windows/Linux/macOS)Python版本选择(3.x推荐版本)解释器…...
Redisson - 实现延迟队列
Redisson 延迟队列 Redisson 是基于 Redis 的一款功能强大的 Java 客户端。它提供了诸如分布式锁、限流器、阻塞队列、延迟队列等高可用、高并发组件。 其中,RDelayedQueue 是对 Redis 数据结构的高阶封装,能让你将消息延迟一定时间后再进入消费队列。…...

软件工程的定义与发展历程
文章目录 一、软件工程的定义二、软件工程的发展历程1. 前软件工程时期(1940s-1960s)2. 软件工程诞生(1968)3. 结构化方法时期(1970s)4. 面向对象时期(1980s)5. 现代软件工程(1990s-至今) 三、软件工程的发展趋势 一、软件工程的定义 软件工程是应用系统化、规范化、可量化的方…...
艾利特协作机器人:重新定义工业涂胶场景的精度革命
品牌使命与技术基因 作为全球协作机器人领域成长最快的企业之一,艾利特始终聚焦于解决工业生产中的人机协作痛点。在汽车制造、3C电子、新能源等领域的涂胶工艺场景中,我们通过自主研发的EC系列协作机器人,实现了: 空间利用率&a…...

第十三节:第五部分:集合框架:集合嵌套
集合嵌套案例分析 代码: package com.itheima.day27_Collection_nesting;import java.util.*;/*目标:理解集合的嵌套。 江苏省 "南京市","扬州市","苏州市","无锡市","常州市" 湖北省 "武汉市","…...

Java设计模式之观察者模式详解
一、观察者模式简介 观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系。当一个对象(主题)的状态发生改变时,所有依赖于它的对象(观察者)都会自…...

freeRTOS 消息队列之一个事件添加到消息队列超时怎么处理
一 消息队列的结构框图 xTasksWaitingToSend:这个列表存储了所有因为队列已满而等待发送消息的任务。当任务尝试向一个已满的队列发送消息时,该任务会被挂起并加入到xTasksWaitingToSend列表中,直到队列中有空间可用, xTasksW…...
十八、【用户认证篇】安全第一步:基于 JWT 的前后端分离认证方案
【用户认证篇】安全第一步:基于 JWT 的前后端分离认证方案 前言什么是 JWT (JSON Web Token)?准备工作第一部分:后端 Django 配置 JWT 认证1. 安装 `djangorestframework-simplejwt`2. 在 `settings.py` 中配置 `djangorestframework-simplejwt`3. 在项目的 `urls.py` 中添加…...
RabbitMQ 开机启动配置教程
RabbitMQ 开机启动配置教程 在本教程中,我们将详细介绍如何配置 RabbitMQ 以实现开机自动启动。此配置适用于手动安装的 RabbitMQ 版本。 环境准备 操作系统:CentOS 7RabbitMQ 版本:3.8.4Erlang 版本:21.3 步骤 1. 安装 Erla…...

Authpf(OpenBSD)认证防火墙到ssh连接到SSH端口转发技术栈 与渗透网络安全的关联 (RED Team Technique )
目录 🔍 1. Authpf概述与Shell设置的作用 什么是Authpf? Shell设置为/usr/sbin/authpf的作用与含义 🛠️ 2. Authpf工作原理与防火墙绕过机制 技术栈 工作原理 防火墙绕过机制 Shell关联 🌐 3. Authpf与SSH认证及服务探测…...

组合与排列
组合与排列主要有两个区别,区别在于是否按次序排列和符号表示不同。 全排列: 从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当mn时所有的排列情况…...
神经网络-Day45
目录 一、tensorboard的基本操作1.1 发展历史1.2 tensorboard的原理 二、tensorboard实战2.1 cifar-10 MLP实战2.2 cifar-10 CNN实战 在神经网络训练中,为了帮助理解,借用了很多的组件,比如训练进度条、可视化的loss下降曲线、权重分布图&…...
【西门子杯工业嵌入式-1-基本环境与空白模板】
西门子杯工业嵌入式-1-基本环境与空白模板 项目资料一、软件安装与环境准备1. 安装MDK52. 安装驱动3. 安装GD32F470支持包 二、工程目录结构建议三、使用MDK创建工程流程1. 新建工程2. 添加工程组(Group)3. 添加源文件 四、编译配置设置(Opti…...

Apache Druid
目录 Apache Druid是什么? CVE-2021-25646(Apache Druid代码执行漏洞) Apache Druid是什么? Apache Druid是一个高性能、分布式的数据存储和分析系统。设计用于处理大量实时数据,并进行低延迟的查询。它特别适合用于分析大规模日志、事件数据…...

使用深蓝词库软件导入自定义的词库到微软拼音输入法
我这有一个人员名单,把它看作一个词库,下面我演示一下如何把这个词库导入微软输入法 首先建一个text文件,一行写一个词条 下载深蓝词库 按照我这个配置,点击转换,然后在桌面微软输入法那右键,选择设置 点…...
Docker快速部署AnythingLLM全攻略
Docker版AnythingLLM安装指南 环境准备 确保已安装: Docker Engine 20.10.14+Docker Compose 2.5.0+验证安装: docker --version && docker compose version安装步骤 创建持久化存储目录: mkdir -p ~/anythingllm/database ~/anythingllm/files运行容器(基础配置)…...

使用Node.js分片上传大文件到阿里云OSS
阿里云OSS的分片上传(Multipart Upload)是一种针对大文件优化的上传方式,其核心流程和关键特性如下: 1. 核心流程 分片上传分为三个步骤: 初始化任务:调用InitiateMultipartUpload接口创建上传任务…...
高性能分布式消息队列系统(四)
八、客户端模块的实现 客户端实现的总体框架 在 RabbitMQ 中,应用层提供消息服务的核心实体是 信道(Channel)。 用户想要与消息队列服务器交互时,通常不会直接操作底层的 TCP 连接,而是通过信道来进行各种消息的发布…...
C#异步编程:从线程到Task的进化之路
一、没有异步编程之前的时候 在异步编程出现之前,程序主要采用同步编程模型。这种模型下,所有操作按顺序执行,当一个操作(如I/O读写、网络请求)阻塞时,整个程序会被挂起,导致资源利用率低和响应延迟高。具体问题包括: 阻塞执行:同步代码在执行耗时操作时(如文件读取…...
[论文阅读] 人工智能+软件工程 | 用大模型优化软件性能
用大模型优化软件性能?这篇论文让代码跑出新速度! arXiv:2506.01249 SysLLMatic: Large Language Models are Software System Optimizers Huiyun Peng, Arjun Gupte, Ryan Hasler, Nicholas John Eliopoulos, Chien-Chou Ho, Rishi Mantri, Leo Deng, K…...

复变函数中的对数函数及其MATLAB演示
复变函数中的对数函数及其MATLAB演示 引言 在实变函数中,对数函数 ln x \ln x lnx定义在正实数集上,是一个相对简单的概念。然而,当我们进入复变函数领域时,对数函数展现出更加丰富和复杂的性质。本文将介绍复变函数中对数函…...