剑指Offer——JZ67.剪绳子【DP | 贪心】

题目传送门


在这里插入图片描述


题解

动态规划:

  • 对于任意 n n ,分解为 f 1 , f 2 , f 3 . . . f k f_1,f_2,f_3 ... f_k 。对于任意 f i , i [ 1 , k ] f_i,i∈[1, k] 继续拆分后,最后都是乘积关系,所以满足无后效性,可以使用动态规划解决。
  • d p [ i ] dp[i] 为长度为 i i 的绳子分解最大值。
  • 那么状态转移方程: d p [ i ] = m a x ( d p [ i ] , d p [ i j ] d p [ j ] ) , d [ 1 , i / 2 ] dp[i] = max(dp[i], dp[i-j] * dp[j]), d∈[1, i/2]

贪心:

  • 其实很好发现:
    • n < = 3 n <=3 的时候,不拆分是最好的,
    • n = = 4 n==4 的时候,拆分|不拆分是一样的,
    • n > = 5 n >= 5 的时候,拆分是最好的。
  • 那么也就是说,最后一定会拆分的结果一定是小于等于 4 4 的。
  • 对于 4 4 ,一定是拆分为 2 2 2*2 是最优解。
  • 那么最后就是在 2 2 3 3 中选择。
  • n > = 5 n>=5 时, 3 ( n 3 ) > = 2 ( n 2 ) 3*(n-3)>=2*(n-2) ,那么就尽可能的按 3 3 分割。
  • 最后剩下的如果是 2 2 ,就直接乘进去,如果是 1 1 ,那就取出一个 3 3 组成 2 2 2*2

AC-Code

DP:

class Solution {
public:
    int cutRope(int number) {
        if(number < 2)    return 0;
        if(number == 2)    return 1;
        if(number == 3)    return 2;
        int *dp = new int[number + 1];
        memset(dp, 0, sizeof(dp));
        dp[1] = 1;    dp[2] = 2;    dp[3] = 3;
        for(int i = 4; i <= number; ++i) 
            for(int j = 1; j <= i / 2; ++j) 
                dp[i] = max(dp[i], dp[i - j] * dp[j]);
        int ans = dp[number];
        delete[] dp;
        return ans;
    }
};

贪心:

class Solution {
public:
    int cutRope(int number) {
        if(number < 2)    return 0;
        if(number == 2)    return 1;
        if(number == 3)    return 2;
        return number % 3 == 1 ? pow(3 , (number/3 - 1)) * 4 : pow(3, (number / 3)) * 2;
    }
};

猜你喜欢

转载自blog.csdn.net/Q_1849805767/article/details/106536803