剑指offer 题14——剪绳子

剪绳子

题目

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

动态规划

我们可以进行这样的分析,假设把长度为n的绳子剪成若干段后得到的乘积最大值为函数f(n)。假设我们把第一刀剪在长度为i(0<i<n)的位置上,于是吧绳子剪成了i和n-i上。我们要想得到最优解f(n),就要用同样的方法得到f(i)和f(n-i),也就是说整体问题的最优解是依赖各个问题的最优解——这是动态规划的重要特性。
首先,定义函数f(n)为把长度为n的绳子剪成若干段后各段长度乘积的最大值.在剪第一刀时,有n-1种可能,第一段长度可能为1,2,…,n-1。因此f(n)=max(f(i)xf(n-1)),其中0<i<n
当长度为2时,只能剪成长度为1的两段,因此f(2)=1。当长度为3时,可能是1和2两段,也可能是三段1。又1x2>1x1x1,因此f(3)=2
有了以上分析,就可以写代码了

int maxProductAfterCutting_solution(int length)
{
    //length 为1,2,3的情况
    if(length<2)   return 0;
    if(length==2) return 1;
    if(length==3) return 2;
    
    //products用来存贮子问题的最优解,第i个元素表示f(i)
    std::unique_ptr<int[]> products(new  int [length +1]); //使用智能指针(包含在<memory>中),可以不用手动释放内存
    products[0]=0;
    products[1]=1;
    products[2]=2;
    products[3]=3;

    int max=0;
    
    for(int i=4;i<=length;++i)
    {
        max=0;
        for(int j=1;j<i/2;++j)
        {
             int product=products[j]*products[i-j]; 
        if(max<product) //求得最大 进行替换
            max=product;
        
        products[i]=max;
        }
    }
    max=products[length];
    return max;
}
贪心算法

如果我们采用如下的策略来剪绳子,则可以得到最优解:
当n>=5时,尽可能多的剪长度为3的绳子;
当剩下的长度为4时,把绳子剪成两段长为2的绳子
由这样的思路可以写出一下代码:

int maxProductAfterCutting_solution(int length)
{
    if(length<2)   return 0;
    if(length==2) return 1;
    if(length==3) return 2;

   //尽可能多的剪出长度为3的子段
        int timesOf3 = length/3;

   //当绳子最后剩下的长度为4的时候,不能再剪去长度为3的绳子段
     //此时更好的方法是把绳子剪成长度为2的两段,因为2x2>3x1
        if(length-timesOf3*3==1)
               timesOf3-=1;
     
          int timesOf2 = (length-timesOf3*3)/2;

          return (int)(pow(3,timesOf3))*(int)(pow(2,timesOf2)) 
}

使用贪婪算法我们需要证明其具有贪婪性,这样才可以用贪婪法进行求解。
现给出以下证明:
首先,当n>=5时,可以证明2(n-2)>n,并且3(n-3)>3。也就是说,当绳子剩下的长度大于或者是等于5时,我们就把它剪成长度为3或者是2的绳子段,另外当n>=5时,3(n-3)>=2(n-2),因此我们应该尽可能地多剪长度为3的绳子段
其次,要是长度为4,剪一刀有两种结果:1和3或者是2和2。由于2x2>1x3并且2x2=4。当绳子为4时其实没必要剪,只是要求至少一刀而已

————————————————————————————————————————————————————————————————
参考书籍《剑指offer》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值