题目描述: 给你一根长度为n的绳子,请把绳子剪成m段(m,n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m]。请问k[0]*k[1]*k[2]*k[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把他剪成2、3、3的三段,此时得到的最大乘积是18。
题目分析:典型的动态规划问题,以及贪心算法问题。
动态规划问题要从上到下分析问题,从下到上进行求解。假设一条长度为n的绳子,我们从i处分割,那么就分成了i,与m-i两段,这两段还要求其分割之后的乘积最大,所以每一步都是要求最优解。大问题能分解成小问题,每个小问题还互相相关联,这样的问题就可以使用动态规划。所以我们要想求第一处该在哪分割就要求解max(f(i)*f(n-i)),0<i<n-1;所以需要从头到尾去求f(i)。可以已知一些条件,当绳子长度为0,1时,都返回0,因为切不了。当绳子长度为2时,返回1,因为切成两半,1*1=1。当绳子长度为3时,返回2,因为可以分割为2,1与1,1,1这两种情况,那么2*1>1*1。
注意:这里没有说f(1)=0,f(2)=1,f(3)=2。为什么呢,因为我们需要判断的情况是当绳子长度为4及其以上的情况,所以,比如以4为例,可以分成1和3,此时1和3都可以不用再切开了,因为不切开时值最大,所以f(1)=1,f(3)=3,f(2)=2。还有一点就是,我们不需要从1判断到n-1,我们可以判断到n/2;因为后半段与前半段是重复的,比如f(1)*f(3)和f(3)*f(1)是相等的。
最后附上动态规划代码:动态规划的时间复杂度为O(n^2),空间复杂度为O(n),不是一个好的算法,所以接下来会写一下贪心算法的解法。
import java.util.*;
public class jianshengzi {
public static void main(String[]args){
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
int he = panduan(n);
System.out.print(he);
}
}
public static int panduan(int n){
if (n<2)
return 0;
if(n==2)
return 1;
if (n==3)
return 2;
int []tt = new int[n+1];
tt[0]=0;
//
tt[1]=1;
//这个tt[2]是作为子段,也就是,它可以不在分段了,所以它的值应为2而非1。
//但是如果绳子长度就为2,必须剪一刀,所以就是1*1=1。这个要注意
tt[2]=2;
tt[3]=3;
//max(tt[i]*tt[n-i])
int max=0;
for (int i=4;i<=n;i++)
{
max=0;
//这里为什么不是<n呢,因为,比如n为4,
//tt[i]*tt[n-i],0<i<n,i可取1,2,3
//为tt[1]*tt[3],tt[2]*tt[2],tt[3]*tt[1]这样后面的就重复了,求一半即可,4的一半是1,2。
for (int j=1;j<=i/2;j++)
{
int t=tt[j]*tt[i-j];
if (max<t)
{
max=t;
}
tt[i]=max;
}
}
return tt[n];
}
}
贪心算法的想法是:首先看这个长度是否大于等于5,如果大于等于5就尽量多的给它分成3,然后剩余的如果等于4就分成2。举个例子。
在代码中:我们先计算出n(长度)/3的值,这就是n包含3的个数我们记为timeof3,然后去判断n%3的值,n%3总共有3种可能,0,1,2,当为0是不考虑。当为1时,说明有4,也就是1+3=4,所以需要把3的个数减去1,然后把2的个数(timeof2)变成2。当为2时,就把2的个数变为1。最后返回3的timeof3次方与2的timeof2次方的乘积。
附上代码:
public static int panduan(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 timeof4=0;
int timeof2=0;
//余0,1,2
//余1则有4,2*2比1*3好,余2没事,余0没事
if (n%3==1)
{
timeof3--;
timeof4++;
}
else if (n%3==2)
{
timeof2++;
}
if (timeof4!=0)
{
timeof2=2;
}
return (int)Math.pow(3,timeof3)*(int)Math.pow(2,timeof2);
}