题目:
把长度为n的绳子剪成m段(n>1,m>1),每段绳子的长度记为k[1],…k[m],则每段绳子的长度的最大乘积是多少?例如身子长度为8时,剪成2,3,3三段得到的乘积最大,为18。
思路:
方法1:动态规划的思想
假设长度为n的绳子被剪成若干段后,各段长度的最大乘积为f(n)。一刀下去可能的位置有1,2,…,n-1,j将绳子分为长度为i和n-i的两段,则f(n)=max{f(i)*f(n-i)},i=1,2,…,n-1。从上往下递归时可能会有很多重复的计算,因此采用从下往上的方式,先计算f(2),f(3),后面的就可以依次计算了。n=2时,只有一种剪法,f(2)=1*1=1,n=3时,只有剪成1,2,f(3)=1*2=2*1=2。
写代码要注意:n=2时,因为必须要剪一刀,只能剪成1和1,所以最大乘积是1,但是初始化f(2)的时候,是为了计算n>3的情况,因此如果有长度为2的肯定至少剪了一刀,这时候长度为2的最大乘积是2,初始化f(3)也是同理。
方法2:贪婪算法的思想
如果按照如下策略来剪绳子,则得到各段绳子的长度的乘积将最大。当n>=5时,尽可能多剪长度为3的绳子,当剩下绳子长度为4时,剪成2*2的两段。
写代码要注意:整除3后余数只有0,1,2三种情况,如果是2,那应该直接2*3^(timeOf3);如果是1,说明多剪了一个3,应该应该拿出来一个3(timeOf3-1)和剩下的1组成4,结果是4*3(timeOf3);如果是0,说明正好每段为3剪完,结果是1*3^(timeOf3)。
方法1代码:
int maxProduct(int n)
{
if(n<=1)
return 0;
int *dp=new int[n+1];
if(n==2)
return 1;
if(n==3)
return 2;
//注意这里的初始化
dp[0]=0;
dp[1]=1;
dp[2]=2;
dp[3]=3;
for(int i=4;i<=n;i++)
{
int maxP=0;
for(int j=1;j<=i/2;j++)
{
int product=dp[j]*dp[i-j];
if(product>maxP)
maxP=product;
}
dp[i]=maxP;
}
int result=dp[n];
delete[] dp;
return result;
}
方法2代码:
int maxProduct(int n)
{
if(n<=1)
return 0;
if(n==2)
return 1;
if(n==3)
return 2;
if(n==4)
return 4;
int timeOf3=n/3;
int result=n-timeOf3*3;//余数
//注意不同余数情况下的处理
if(result==0)
result=1;
if(n-timeOf3*3==1)
{
timeOf3-=1;
result=4;
}
for(int i=1;i<=timeOf3;i++)
{
result=result*3;
}
return result;
}