【剑指offer】剪绳子
题目链接:剪绳子
题意:给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m]。请问k[0]xk[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
题解:
1、dp做法。每段绳子都能分割成它的乘积。因此,动态转移方程dp[i] = max{dp[i],dp[j] * dp[i-j]}.
这里要注意的是,绳长 = 2 / 3时,它们是必须要分割的(m>1),所以特殊讨论。
len = 2,分割就是 1 1,所以乘积为1。
len = 3,分割就是 1 2,所以乘积为2 。
一旦len>3了,那前面的就相当于是作为len里的分割元素,也就是dp[2]=2,dp[3]=3.
2、贪心。每个数字(>3)都能分解成有n个2和n个3的相加。举例,
4:2+2
5:2+3
6:3+3
7:2+2+3
8:2+2+2+2
所以我们直接贪心,看数字里含多少个3再去看除去3以后含多少个2。
要考虑一下有4的情况,此时要分解成2+2而不是1+3。因此对于像7,10这种数,做一个特判。
代码:
1 class Solution { 2 public: 3 int dp[105]={0}; 4 int cutRope(int number) { 5 if(number == 2) return 1; 6 if(number == 3) return 2; 7 dp[0] = 0; dp[1] = 1; 8 dp[2] = 2; dp[3] = 3; 9 for(int i = 4 ;i <= number; i++){ 10 for(int j = 1; j <= i/2; j++){ 11 dp[i] = max(dp[i],dp[j]*dp[i-j]); 12 } 13 } 14 return dp[number]; 15 } 16 }; 17 18 19 OR 20 21 22 class Solution { 23 public: 24 int cutRope(int number) { 25 if(number == 2) return 1; 26 if(number == 3) return 2; 27 int cnt = number/3; //含3的个数 28 if(number - cnt*3 == 1) //保证最后有4的情况是2*2 29 cnt--; 30 int cntt = (number - 3*cnt)/2; //2的个数 31 int ans = pow(3,cnt)*pow(2,cntt); 32 return ans; 33 } 34 };