内容:
给定一根长度为n的绳子,请把绳子剪成m段,每段绳子记为k[0],k[1]……k[m]。请问k[0]*k[1]……*k[m]可能的最大乘积是多少?例如:当绳子长度为8时,我们把它剪成长度分别为2,3,3段,此时最大乘积为18.
解题思路:
思路一:我们先考虑能否把大问题分解成小问题,分解后的小问题也存在最优解,如果把小问题的最优解组合起来能否是整个问题的最优解,这就是动态规划求解。我们把绳子从第i(i<n)处的位置开始剪,把长度分为i和n-i,要得到最优解用同样的方法把长度为i和n-i的两段分别剪成若干段。在这里用动态规划是因为:在分解问题的时候,子问题会在分解的过程中重复出现,如,长度为10的绳子剪成长度为4和6两段,即f(4)和f(6),分别再求两个子问题把4剪成均为2的两段f(2)和f(2),把6剪成两段2和4,即f(2)和f(4),这时f(2)是f(4)和f(6)公用的更小子问题,这时用动态规划从上往下分析问题,从下往上解决问题。空间复杂度为O(n),时间复杂度为O(n^2)
代码实现:
int maxlength(int a[],int length) { if (length < 2) return 0; if (length == 2) return 1; if (length == 3) return 2; int i = 4; while (i <= length){ int j = 1; while (j <= i / 2){ if (a[j] * a[i - j]>a[i]) a[i] = a[j] * a[i - j]; j++; } i++; } return a[length]; } main()函数中传入的数组的初始化值应该是{0,1,2,3},并且长度大于绳子的长度
思路二:
从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止,这就是贪婪算法。在剪绳子中,如果绳子的长度大于5,则每次剪出的长度为3的绳子。如果剩下的长度仍然大于5,则接着剪出一段长度为3的绳子,重复这个步骤,直到剩下的长度小于5.时间和空间复杂度都为O(1)。
代码实现:
int maxlength(int length) { if (length < 2) return 0; if (length == 2) return 1; if (length == 3) return 2; int timesOf3 = length / 3; //剪长度为3的绳子段 if ((length - timesOf3 * 3)==1) //当长度为4的时候不能去用3剪 timesOf3 -= 1; int timesOf2= (length - timesOf3* 3) / 2; // 这时应该把绳子剪成长度为2的两段:2*2>1*3 return ((int)(pow(3, timesOf3))*((int)pow(2, timesOf2))); }