剪绳子(贪心/动态规划)

准备找工作,开始刷题,牛客剑指offer

链接:https://www.nowcoder.com/questionTerminal/57d85990ba5b440ab888fc72b0751bf8?f=discussion
 

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

输入描述:

输入一个数n,意义见题面。(2 <= n <= 60)

输出描述:

输出答案。

示例1

输入

8

输出

18

题解:

方法一:

  • 贪心算法:这种想法比较巧妙,尽量把大于5的数分解成3的乘积,如果剩下的长度为4,则把4分解成2和2,因为3*1<2*2

方法二:

  • 利用动态规划,需要O(n^2)时间和O(n)空间,也就是利用一个表,储存长度为1~n绳子的最大乘积。

代码:

#include<bits/stdc++.h>

using namespace std;

//贪心
int cutRope1(int number) {
    if(number == 2)
        return 1;
    if(number == 3)
        return 2;
    int a = number % 3;   //计算余数
    int b = number / 3;   //计算有多个3
    
    if(a == 0)          //余数为0时,所有3乘积即是结果;  例如9: 3*3*3
        return pow(3,b);
    else if(a == 1)     //余数为1时,应将1*3分解成2*2;    例如10: 3*3*2*2
        return pow(3,b-1) * 4;
    else if(a == 2)
        return pow(3,b) * 2;   //余数为2时,直接将结果*2; 例如11: 3*3*3*2
}

//动态规划
int cutRope2(int number) {
    int dp[65];
    dp[1] = 1;
    dp[2] = 2;
    dp[3] = 3;

    int res = -1;
    for(int i = 4; i <= number; i++) {
        for(int j = 1; j <= i/2; j++) {         //计算1到i的一半,因为后一半计算的值相同
            res = max(res,dp[j]*dp[i-j]);       //比如dp[1]*dp[4-1]  和  dp[3]*dp[4-3]
        }
        dp[i] = res;
    }
    return dp[number];
}

int main()
{
    int n,m;
    cin >> n;
    while(n--) {
        cin >> m;
        cout << cutRope2(m) << endl;
    }
    return 0;
}

好了,总结一下吧;这道题我也做了很久,最后找了找规律,利用动态规划做出来;然后看题解发现贪心方法是真的挺妙的,相比动态规划更容易理解,并且时间、空间方面都略胜动态规划。嗯嗯…刷其它题去了

 

猜你喜欢

转载自blog.csdn.net/qq_41216743/article/details/103974197