给你一根长度为n的绳子,把绳子剪成若干段(每段长为整数),使得这些绳子的长度之积最大,求可能的最大乘积是多少?
法一 动态规划
记忆化搜索(递归法)
时间复杂度:O(n^2),空间复杂度O(n)
(1)当绳子长度小于2,无法剪。
(2)当绳子长度为2,剪为1*1,结果是1
(3)当绳子长度为3,剪为2*1,结果为2
(4)当绳子长度大于等于4时,使用动态规划,用a[i]来表示把长度为i的绳子剪开之后乘积的最大值。初始化a[1]=1,a[2]=2,a[3]=3,其余的为-1
求a[i]的最大值,就是求a[j]a[i-j]的最大值,j的范围为1-i-1。然后展开记忆化搜索即可。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=1005;
int a[maxn];
int n;
//记忆化搜索
int solve(int i)
{
if(a[i]!=-1)
return a[i];
else
{
int max_temp=-1;
//本来j可以取到i-1,但是为了避免重复,就折半处理了
for(int j=1;j<=i/2;j++)
{
int temp=solve(j)*solve(i-j);
max_temp=max(max_temp,temp);
}
a[i]=max_temp;
return a[i];
}
}
int main()
{
cin>>n; //把长度为n的绳子剪为m段,m,n都是整数且都大于1
fill(a,a+n+1,-1);
int res;
//本身长度太小
if(n<2)
res=0;
//剪为1*1
else if(n==2)
res=1;
//剪为2*1
else if(n==3)
res=2;
//长度大于3
else
{
//solve(n)=max(solve(i)*solve(n-i))
//0<i<n
//solve(i)表示把长度为i的绳子剪为若干段之后乘积的最大值
a[1]=1;
a[2]=2;
a[3]=3;
res=solve(n);
}
cout<<res<<endl;
}
法二 贪心算法
时间复杂度/空间复杂度 O(1)
当绳子长度大于等于5时,尽可能多剪长度为3的绳子,当长度为4时,剪为2*2即可。
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n;
cin>>n;
int res;
if(n<2)
res=0;
else if(n==2)
res=1;
else if(n==3)
res=2;
else
{
//长度为3的段数
int timesof3=n/3;
//如果有4的段数,剪为2*2
if(n-timesof3*3==1)
timesof3-=1;
int timesof2=(n-timesof3*3)/2;
res=pow(3,timesof3)*pow(2,timesof2);
}
cout<<res<<endl;
return 0;
}
当绳子大于等于5时,可以证明2(n-2)>n,且3(n-3)>n。即当绳子剩下的长度大于等于5时,可以把它剪为长度为3或2的绳子段,另外n>=5,有3(n-3)>=2(n-2),因此可以尽可能多剪长度为3的绳子段。