剑指offer-剪绳子问题

给你一根长度为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的绳子段。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值