给你一根长度为 n 的绳子,请把绳子剪成整数长的 m 段( m 、 n 都是整数, n > 1 并且 m > 1 , m <= n ),每段绳子的长度记为 k[1],...,k[m] 。请问 k[1]*k[2]*...*k[m] 可能的最大乘积是多少?例如,当绳子的长度是 8 时,我们把它剪成长度分别为 2、3、3 的三段,此时得到的最大乘积是 18

思路一:动态规划

设计一个数组len[N],用于存放长度为N的绳子裁剪后所能拥有的最大乘积。

如len[1]表示长度为1的绳子的最大值,len[2]表示长度为2的最大值。

由于长度为2只能剪一刀,故len[2]固定为1;

当len大于2时,则可以用两层循环,外层循环表示绳子的长度,里层循环用于表示本次所裁剪的绳子的长度,由于裁剪绳子长度不能超过当前绳子总长度,故内层结束条件为裁剪绳子长度等于绳子长度。所有裁剪结果中的最大值,就是当前长度绳的最大乘积。

具体实现:

   int cutRope(int n) {
        // write code here

        vector<int>dp(n+1,0);
      
        dp[2]=1;
        for(int i=3;i<=n;i++)
        {

         for(int j=2;j<i;j++)
         {
            dp[i]=max(dp[i],max(dp[i-j]*j,(i-j)*j));
         }

        }
        return dp[n];
    }

本题不好理解的点在“dp[i]=max(dp[i],max(dp[i-j]*j,(i-j)*j))”这一部分,其中max里的dp[i]表示剪2到j-1长度里的最大值,后面的max表示剪长度j的最大值,之所以再细分为两部分,是由于dp[i-j]*j默认对i-j部分又进行了裁剪,而(i-j)*j则表示未对该分部再进行裁剪。

 

思路二:数学分析

对于1到9的数字,1无法再分解,2分解后乘积最大为1,3分解后乘积最大为2,故2和3不分解的时候更大,对于4到9分解后最大情况如下:

4=2+2,  5=2+3,6=3+3, 7=3+2+2, 8=3+3+2, 9=3+3+3,可见对于任意一个数字,分解成一堆3和2时乘积最大,即拆分后的结果不能大于3,因为拆分后的数字大于3,则继续拆分可以乘积更大,而都可以拆分成3和2,为了使乘积结果更大,应该尽可能先拆3,最后再拆2.

具体代码如下:

int cutRope(int n) {
    // write code here
    if (n == 2)
    {
        return 1;
    }
    int mul = 1;
    if (n % 3 != 1)
    {
        while (n > 3)
        {
            mul *= 3;
            n -= 3;
        }
        mul *= n;
    }
    else {
        return 4 * pow(3, (n - 4) / 3);
    }
    return mul;

}

由于4拆分成2*2相比拆出3能得到更大的乘积,因此对于模3取余为1的数,拆3到最后一定会留下一个4,故可以先拆一个4,剩余的再拆3,故出现了if条件分支。

点击阅读全文
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐