【剑指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.

 

动态规划

  总是从解决最小问题开始,并把已经解决的子问题的最优解存储下来(一维或二维数组),并把子问题的最优解组合起来逐步解决大的问题。

  动态规划的特点:

  1. 问题的目标是,求一个问题的最优解:问题的目标是求剪出各段绳子长度的乘积最大值
  2. 整体问题的最优解是以来各个子问题的最优解:把第一刀剪在i的位置,绳子分为i和n-i;用同样优化的方法把i和n-i分别剪成若干段......依此类推
  3. 把大问题分解为若干个小问题,小问题之间还有互相重叠的更小子问题:假设绳子起初长度为10,第一刀分为4和6;第二刀分4的,得两段2;第三刀分6的,得2和4......那么f(2)是f(4)和f(6)的公共子问题
  4. 从上到下分析问题,从下往上求解问题:避免重复求解子问题

 

贪婪算法

  每一步都可以做出一个贪婪的选择,基于这个选择,可以得到最优解。

  比如长度为10的绳子,如果绳子长度大于3,则剪长度为3的段,若剩余绳子长度仍大于3,则继续剪3的段......直到剩余的绳子长度小于3  

 

//动态规划

  f(n) = max(f(i) * f(n-i)) , 0<i<n

    为了避免重复子问题,先得到f(2),f(3)再得到f(4),f(5)......

  当绳子长度为2的时候,只能剪两段1 ===> f(2) = 1;

  当绳子长度为3的时候,能剪一段2和一段1 或者 三段1 ===> 1*2 > 1*1*1  ===>  f(3) = 2

class Solution {
public:
    int maxProductAfterCutting_solution(int length) {
        if(length < 2)
        {
            return 0;
        }
        if(length == 2)
        {
            return 1;
        }
        if(length == 3)
        {
            return 2;
        }
        
        //子问题的最优解存储在数组product中
        int *product = new int[length + 1];
        product[0] = 0;
        product[1] = 1;
        product[2] = 2;
        product[3] = 3;
        //product[i]的第i个元素表示把长度为i的绳子剪成若干段后各段长度乘积的最大值,f(i)
        int max = 0;
        //求i之前对于每个j,f(j)都已经求解出来了,并且结果保存在product[j]里
        for(int i = 4; i <= length; i++)
        {
            //求出所有可能的f(j)*f(i-j)并比较它们的最大值
            max = 0;
            for(int j = 1; j = i / 2; j++)
            {
                int tmp = product[j] * product[i - j];
                if(max < tmp)
                {
                    msx = tmp;
                }
                product[i] = max;
            }
        }
        max = product[length];
        delete[] product;
        
        return max;
        
    }
};

  

 

//贪婪算法

  当n>=5时,尽可能多地剪长度为3的绳子,当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子

class Solution {
public:
    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的时候:把绳子剪成长度为2的两段,因为2*2 > 1*3
        if((length - timesOf3 * 3) == 1)
        {
            timesOf3 -=1;
        }
        int timesOf2 = (length - timesOf3 * 3) / 2;
        
        //返回 x 的 y 次幂。
        return ((int)(pow(3,timesOf3)) * (int)(pow(2,timesOf2)));
    }
};

  

 

posted @ 2019-08-26 22:28  XieXinBei0318  阅读(247)  评论(0编辑  收藏  举报