一.题目
给你一根长度为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。
二.思路
我们首先看一下该问题是否符合动态规划的4个特征:
- 求一个问题的最优解
- 整体问题的最优解依赖于各个子问题的最优解
- 小问题之间还有相互重叠的更小的子问题
- 从上往下分析问题,从下往上解决问题
经分析,该问题具有以上4个特征,可以使用动态规划算法
同时,从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止,这就是贪心算法。在剪绳子中,如果绳子的长度大于5,则每次剪出的长度为3的绳子。如果剩下的长度仍然大于5,则接着剪出一段长度为3的绳子,重复这个步骤,直到剩下的长度小于5.时间和空间复杂度都为O(1)。
三.代码
- 动态规划
//动态规划 int maxProductAfterCutting_solution(int length){ if(length < 2) return 0; if(length == 2) return 1; if(length == 3) return 2; int* prooducts = new int[length+1]; //下面都是子问题的最优解,注意子问题是可以不分段的,所以product[3]=3而不是2 products[0] = 0; products[1] = 1; products[2] = 2; products[3] = 3; int max = 0; for(int i = 3;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]; delete[] products; return max; }
- 贪心算法
//贪心算法 int maxProductAfterCutting_solution2(int length){ if(length < 2) return 0; if(length == 2) return 1; if(length == 3) return 2; //尽可能多的剪出长度为3的绳子 int timeOf3 = length / 3; //当绳子最后剩下的一段长度为4的时候,不再分为3+1而是4+0,因为f(3)*f(1) = 3 < f(2) * f(2) if(length - 3 * timeOf3 == 1) timeOf3--; int timeOf2 = (length - 3*timeOf3) / 2; return (int)(pow(3,timeOf3)) *(int)(pow(2,timeOf2)); }
四.本题考点
- 考察应聘者的抽象建模能力。应聘者需要把一个具体的场景抽象成一个能够用动态规划或者贪心算法解决的模型。
- 考查应聘者对于动态规划和贪心算法的理解。能够灵活运用动态规划解决问题的关键是具备从上到下分析问题、从下到上解决问题的能力,而灵活运用贪心算法则需要扎实的数学基本功。