[Leetcode] 343. Integer Break 解题报告

探讨了如何将一个正整数拆分成至少两个正整数之和,以使得这些整数的乘积最大化的问题。提出了两种解决方案:动态规划和递推法,并通过数学证明解释了为何拆分为3能获得最大乘积。

题目

Given a positive integer n, break it into the sum of at least two positive integers and maximize the product of those integers. Return the maximum product you can get.

For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return 36 (10 = 3 + 3 + 4).

Note: You may assume that n is not less than 2 and not larger than 58.

思路

1、动态规划:我们定义dp[i]表示i可以被分解的整数所能形成的最大乘积,那么其状态转移方程为:dp[i] = max(max(j, dp[j]) * max(i - j, dp[i - j])),其中1 <= j <= i / 2。为什么在max函数里面还需要嵌套一个max函数呢?这是因为对于正整数j,我们既可以不对它进行分解(也就是直接返回j),也可以将它分解为至少两个正整数的乘积(也就是返回dp[j])。动态规划的算法的时间复杂度是O(n^2),空间复杂度是O(n)。

2、递推法:小榕流光在博客http://blog.csdn.net/qq508618087/article/details/51289912中发现,如果n>4那么n可以一直取3直到n<=4, 这样的乘积最大。依据这个观察可以写出更加简洁和高效的递归代码。那么为什么这个观察是正确的呢?我后来看到一个很不错的证明(http://blog.csdn.net/camellhf/article/details/52733400),这里贴出来供大家参考:

1)拆出来的数只能是2和3,而不会大于3。这是因为如果拆出4,那么4可以进一步拆出2*2,最终结果不变;如果拆出5,那么5可以拆出2*3 > 5,进一步将5拆分会获得更大的值。6,7,8...之后的数我们均可以验证不会直接出现。

2)为什么尽可能地拆分为3就能获得最大的数呢?假设x = 3m + 2n,那么y = 3^m * 2^n = 3^m * 2^((x - 3m)/2)。我们对等式两边取对数:ln(y) = m * ln3 + ((x - 3m) / 2) * ln2 = x / 2 * ln2 + (ln3 - 3 / 2 * ln2) * m。其中x是一定的,并且(ln3 - 3 / 2 * ln2) > 0,所以ln(y)是关于m的增函数,也就是3的数目越大,y越大。

所以在实现的过程中,2,3,4这三种情况单独处理,其它情况就不断地拆分3,直到剩下的数在区间[2,4]之内。该算法的时间复杂度是O(n / 3) = O(n)。

代码

1、动态规划:

class Solution {
public:
    int integerBreak(int n) {
        vector<int> dp;
        dp.push_back(0);    // dp[0]
        dp.push_back(1);    // dp[1]
        dp.push_back(1);    // dp[2]
        for(int i = 3; i <= n; ++i) {
            int max_value = 1;
            for(int j = 1; j <= i / 2; ++j) {
                int product1 = dp[j] > j ? dp[j] : j;
                int product2 = dp[i - j] > (i - j) ? dp[i - j] : (i - j);
                int value = product1 * product2;
                if(value > max_value) {
                    max_value = value;
                }
            }
            dp.push_back(max_value);
        }
        return dp[n];
    }
};

2、递推法:

class Solution {
public:
    int integerBreak(int n) {
        if(n <= 2) {
            return 1;
        }
        else if (n == 3) {
            return 2;
        }
        int sum = 1;
        while(n > 4) {
            sum *= 3;
            n -= 3;
        }
        sum *= n;
        return sum;
    }
};
内容概要:本文围绕“基于交流潮流的电力系统多元件N-k故障模型研究”展开,深入探讨了利用Matlab代码实现电力系统在发生多个关键元件同时故障(即N-k故障)情况下的交流潮流计算与故障分析方法。该模型不仅考虑了传统潮流方程的非线性特性,还引入了故障约束条件,能够精确模拟复杂多样的故障场景,如短路、断线等,进而评估电网在极端运行条件下的稳态与动态行为。研究通过构建典型电力系统算例,验证了所提模型在故障筛选、脆弱性识别及系统恢复策略制定方面的有效性,为电力系统安全评估、风险预警和防御体系构建提供了坚实的理论依据和技术支撑。此外,模型具备良好的扩展性,可进一步应用于连锁故障传播分析、恶意攻击模拟等高级安全分析领域。; 适合人群:具备电力系统分析基础理论知识和Matlab编程能力的高校研究生、科研院所研究人员以及电力公司从事电网规划、运行与安全管理的技术人员,特别适用于开展电力系统安全稳定、可靠性评估与应急响应机制研究的专业人士。; 使用场景及目标:①开展电力系统在多重故障条件下的交流潮流仿真,评估系统电压稳定性、线路过载风险及负荷损失程度;②识别电网中的关键薄弱环节与脆弱元件,支撑电网加固改造与防御资源配置;③用于科研项目中的故障场景建模与算法验证,或作为教学案例帮助学生理解复杂故障下的系统响应机制。; 阅读建议:此资源以Matlab代码为核心实现手段,建议读者结合理论推导与代码实现进行对照学习,重点关注故障建模过程中雅可比矩阵的修正方法、故障注入方式及收敛性处理策略,建议在仿真中逐步增加故障数量与复杂度,深入理解N-k故障对系统潮流分布的影响规律,并尝试将其拓展至含新能源接入的现代电力系统场景中进行验证与优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值