DP之剪绳子

题目描述

https://leetcode-cn.com/problems/jian-sheng-zi-lcof/
(leetcode14)
给你一根长度为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

解析:

一.确定状态

动态规划问题,自顶向下思考,自底向上实现,所以考虑实现的最后一步即可得到状态转移方程.
①最后一步

  • 最优策略一定是长度为n的绳子分成m段的乘积最大
  • 一定有最后一段绳子长度为i
  • 除掉这一段绳子,剩下的绳子长度为(n-i)
  • (n-i)的长度的绳子分段后乘积最大

②子问题

  • (n-i)长度的绳子分成k段的乘积最大
  • 原问题是长度为n的绳子分成m段的乘积最大
  • 状态:f(x)=长度为x的绳子分成y段后乘积最大
  • 最后一段的长度是未知的,但是只能是[1-x-1]

二.转移方程

f(i) = max(j*f(i-j)) (j为1到i-1)

三.初始条件和边界条件

①初始条件:f[0]=0,f[1]=1,f[2]=2,f[3]=3
②边界条件: 如果绳子长度小于4需要直接得到结果 (因为在参与计算的时候,可以不对另一部分进行分段)
这里需要注意: 因为这种方法已经默认至少分为两段,所以求解f(i) = max(j*f(i-j))时f(i-j)可以不分段,所以要找到分段与不分段的最大乘积相同的那个长度作为起始长度x,小于x的长度直接给出结果,大于x的长度计算得到,所以它的数组初始化到长度为3时,长度为3时不分段最长.

四.计算顺序

从小到大.当计算f[6]时,f[4]f[5]都已经计算出来了.

Solution1:

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

2020/4/9补充:
剪绳子2

题目描述:

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m] 。请问 k[0]k[1]…*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/

题目解析:

考虑数据爆炸问题,采用贪心算法。当n小于4时直接返回,当n大于4时考虑它切出一段为m,当m小于4时它是不用再切分的,当m为3时为最大不切分值,所以以3为分界值进行切割。

Solution:

class Solution {
public:
    int cuttingRope(int n) {
        const int inf = 1e9+7;
        if(n<2) return 0;
        if(n == 2) return 1;
        if(n == 3) return 2;
        long long ans = 1;
        while(n>4)
        {
            ans = (ans*3)%inf;
            n = n-3;
        }
        return (ans*n)%inf;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C++中,绳子问题是一个经典的动态规划问题。问题描述为:给定一根长度为n的绳子,要求将其成m段(m>1),每段绳子的长度记为k, k, ..., k[m-1],请问如何绳子使得各段绳子的乘积最大? 解决这个问题的一种常见方法是使用动态规划。具体步骤如下: 1. 定义一个数组dp,其中dp[i]表示长度为i的绳子成若干段后各段绳子长度乘积的最大值。 2. 初始化dp数组,dpdp都为0,因为长度为0和1的绳子无法断。 3. 从长度为2开始遍历到n,对于每个长度i,计算dp[i]的值。 - 遍历j从1到i-1,表示第一段绳子的长度,可以取值范围为1到i-1。 - 计算第一段绳子长度为j时,剩余绳子的长度为i-j。 - 计算当前情况下的乘积,即j * dp[i-j]。 - 更新dp[i]的值为所有情况中乘积最大的值。 4. 最终dp[n]即为所求的结果,表示长度为n的绳子成若干段后各段绳子长度乘积的最大值。 下面是绳子问题的C++代码示例: ```cpp #include <iostream> #include <vector> using namespace std; int cutRope(int n) { if (n <= 1) { return 0; } vector<int> dp(n + 1, 0); for (int i = 2; i <= n; i++) { for (int j = 1; j < i; j++) { dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j])); } } return dp[n]; } int main() { int n = 8; int result = cutRope(n); cout << "将长度为" << n << "的绳子成若干段后各段绳子长度乘积的最大值为:" << result << endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值