zoukankan      html  css  js  c++  java
  • (转)最大乘积分析(切绳子)

    原题

    一根绳子,长度为n米。将其切成几段,每一段的长度都是整数。请给出一种切法,使得切成的各段绳子之间的乘积是最大的。注意,最少要切一下的。

    分析

    这个题目如何一步一步的分析呢?不管切几段,总有第一段,第二段…等等。第一段的长度有哪些选择呢?可以是1、2、3...一直到n-1(至少要切一下),我们用max_prod(n)表示长度为n的绳子的切法中,乘积最大的值。那么:

    1.当第一段长度为1时,最大的乘积为:max(1×max_prod(n-1),1×(n-1))2.当第一段长度为2时,最大的乘积为:max(2×max_prod(n-2),2×(n-2))3.4.当第一段长度为n-1时,最大的乘积为:(n-1)*1=n-1

    上面为什么是取max呢?注意,题目中的要求,至少是要切一下的。这样,从上面的分析中得出,递归的表达式,设第一段绳子的长度为i,取 值范围为[1,n-1],则,对于每一个i,有最大乘积为:max(i×(n-i),i×max_prod(n-i))。然后对所有的i,求的最大值,就 是最终的答案。

    这个题目到这里完了么?看过我们以前分析的同学,很快就能想到,进而查看,这些子问题中是否有重复的,如果有,则可以采用动态规划的方法进行算法改 进。而查看是否有重复递归子问题,一个比较好的方法,就是在纸上画出递归树,然后是否有重复的递归子问题。就一目了然了。这个题目是比较明显的,同学们可 以尝试自己在纸上画画,练习一下。

    既然,我们已经明确了重复的递归子问题,然后呢?相信专门学习过动态规划专题的同学,都会记得这样的一句话:“自顶向下的分析问题,自底向上的解决 问题”,大概类似,可能并不是原话。自底向上解决问题的意思就是先解决小问题,然后依据这些小问题的结果,再解决一批问题,依次直至解决整个问题:

    1.当绳子的长度为1的时候,忽略,不能切2.当绳子的长度为2的时候,切一刀,max_prod[2]=1×13.当绳子的长度为3的时候,切一刀,max_prod[3]=1×24.当绳子的长度为4的时候,依赖前面每一个长度的切法,并且,第一个长度从2开始。5.

    这个,状态转移方程可以表示为:max_prod[i]=max((i-j)×j, j×max_prod[i-j]),其中j的范围是[1,i/2]。显然,动态规划方法的时间复杂度为O(n^2),空间复杂度为O(n)。

    这个问题,到这里,已经挺不错的。不过,还没完,这个题目是有更加巧妙的方法的。在微博上,有的同学给出了如下的方法:只需要将长度n表示为 3x+2y=n,并且3尽可能的多,这样的3^x+2^y是最大的。不得不赞叹,这确实是一个很巧妙的方法。大家可以通过例子,验证几个。为什么只有3和 2呢?长度为4的,就是2×2,5以上的,都可以分解为3x+2y,并且3^x+2^y>5以上的数字。这个题目要求是整数,如果取消这个限制呢? 拓展思路,举一反三,请大家多多思考。

    还有一道相似的题目:可以对比得到自己的思路。

    一根绳子长n米。将其切成几段(至少切一下),每段长度都是整数。请给出一种切法,使得切成的各段绳子之间的乘积是最大的。(即自然数N分解为n个自然数的和,求这n个数的乘积最大值

    思路:动态规划

    分析:最优问题,可以用动态规划求解
    1、描述最优解结构
        N = a1 + a2 + ... + an;
        M = a1 * a2 * ... * an;
    求M的最大值
        考虑到N = a + b,而a与b又可以分解为另外几个和为a或b的数的积,因此对于确定的N = a + b,有一个最优解M(N) = M(a)*M(N-a)。而a又有1到N/2种取值,所以有一般最优解M(N) = max{M(a) + M(N - a)}(a < N/2)。而对于1、2、3、4、5等的M值列一个表,就可以得到N<=4时,M(N) = N。于是有下列递归定义。
    2、递归定义最优解
     
       动态规划求解:一个数分解为n个数的和,求n个数积最大 - 埋香 - 低眉浅谈
    代码:
    复制代码
        public static int M(int N){
            int max=0;
            int temp=0;
            if(N<=4)
                return N;
            else{
                for(int i=1;i<=N/2;i++){
                temp=M(i)*M(N-i);
                if(temp>max)
                    max=temp;
            }
            return max;}
        }
    复制代码
  • 相关阅读:
    vue+element目录树默认展开和选中
    vue+element目录树初始化和销毁
    vue父组件通过ref获取子组件的值
    [moka同学笔记转载]Yii2使用$this->context获取当前的Module、Controller(控制器)、Action等
    [moka同学笔记]JS学习 鼠标事件
    [moka同学笔记]phpStudy for Linux (lnmp+lamp一键安装包)
    [转载]php中序列化与反序列化
    [Node.js学习]初之体验
    [moka同学笔记转载]Yii 设置 flash消息 创建一个渐隐形式的消息框
    [moka同学笔记转载]yii2.0 rbac权限学习笔记
  • 原文地址:https://www.cnblogs.com/tianzibobo/p/3402681.html
Copyright © 2011-2022 走看看