首页 > 试题广场 >

剪绳子

[编程题]剪绳子
  • 热度指数:257554 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
给你一根长度为 n 的绳子,请把绳子剪成整数长的 m 段( m 、 n 都是整数, n > 1 并且 m > 1 , m <= n ),每段绳子的长度记为 k[1],...,k[m] 。请问 k[1]*k[2]*...*k[m] 可能的最大乘积是多少?例如,当绳子的长度是 8 时,我们把它剪成长度分别为 2、3、3 的三段,此时得到的最大乘积是 18 。

数据范围:
进阶:空间复杂度 ,时间复杂度

输入描述:
输入一个数n,意义见题面。


输出描述:
输出答案。
示例1

输入

8

输出

18

说明

8 = 2 +3 +3 , 2*3*3=18 
示例2

输入

2

输出

1

说明

m>1,所以切成两段长度是1的绳子    
推荐
//
// Created by yuanhao on 2019-9-3.
//

#include <iostream>
#include <cmath>

using namespace std;

/**
 * 题目分析:
 * 先举几个例子,可以看出规律来。
 * 4 : 2*2
 * 5 : 2*3
 * 6 : 3*3
 * 7 : 2*2*3 或者4*3
 * 8 : 2*3*3
 * 9 : 3*3*3
 * 10:2*2*3*3 或者4*3*3
 * 11:2*3*3*3
 * 12:3*3*3*3
 * 13:2*2*3*3*3 或者4*3*3*3
 *
 * 下面是分析:
 * 首先判断k[0]到k[m]可能有哪些数字,实际上只可能是2或者3。
 * 当然也可能有4,但是4=2*2,我们就简单些不考虑了。
 * 5<2*3,6<3*3,比6更大的数字我们就更不用考虑了,肯定要继续分。
 * 其次看2和3的数量,2的数量肯定小于3个,为什么呢?因为2*2*2<3*3,那么题目就简单了。
 * 直接用n除以3,根据得到的余数判断是一个2还是两个2还是没有2就行了。
 * 由于题目规定m>1,所以2只能是1*1,3只能是2*1,这两个特殊情况直接返回就行了。
 *
 * 乘方运算的复杂度为:O(log n),用动态规划来做会耗时比较多。
 */
long long n_max_3(long long n) {
    if (n == 2) {
        return 1;
    }
    if (n == 3) {
        return 2;
    }
    long long x = n % 3;
    long long y = n / 3;
    if (x == 0) {
        return pow(3, y);
    } else if (x == 1) {
        return 2 * 2 * (long long) pow(3, y - 1);
    } else {
        return 2 * (long long) pow(3, y);
    }
}

//给你一根长度为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 <= 100)
//
//
//输出描述:
//输出答案。
//示例1
//输入
//8
//输出
//18
int main() {
    long long n = 0;
    cin >> n;
    cout << n_max_3(n) << endl;
    return 0;
}

编辑于 2021-07-06 10:46:45 回复(61)
动态规划的时间复杂度可以只是$O(N)$,因为任意一段长度i≥4的绳子,它的dp[i]都是由2、3这两个长度段构成的。剪绳子时,只要对长度为2、3这两种情况计算即可,无需遍历所有可能。
```java
public int cutRope (int n) {
        // write code here
        int[] dp = new int[n+1];
        if (n == 2)
            return 1;
        if (n == 3)
            return 2;

        dp[1] = 1;
        dp[2] = 2;
        dp[3] = 3;
       
        for (int i = 4; i <= n; i++)
            dp[i] = Math.max(dp[i-2]*dp[2], dp[i-3]*dp[3]);

        return dp[n];
    }
```
编辑于 2024-02-24 13:27:57 回复(0)
这题关键是观察规律
    public int cutRope (int n) {
        int res=1;
        if(n<=4) return n;
        while (n>4){
            res*=3;
            n-=3;
        }
        res*=n;
        return  res;
    }


发表于 2023-09-15 14:24:59 回复(0)
public class Solution {
    //质数相乘最大
    boolean flag = false;
    public int cutRope(int target) {
        if (target> 3) {
            flag = true;
        }
        if (!flag) {
            if (target == 2) {
                return 1;
            }
            if (target == 3) {
                return 2;
            }
        }
        if (target == 2) {
            return 2;
        }
        if (target == 3) {
            return 3;
        }
        if (target - 3 >= 3) {
            return cutRope(3)*cutRope(target - 3);
        }
        return cutRope(2)*cutRope(target - 2);
       
    }
}

发表于 2023-02-09 16:08:39 回复(0)
1、动态规划

public class Solution {
    public int cutRope(int n) {

int []dp=new int[n+1];
dp[1]=1;//长度为1的绳子 最大乘积1

//求长度为i的绳子 在至少剪一刀时 得到的最大乘积 
for(int i=2;i<=n;i++){

  //求do[i]
for(int j=1;j<i;j++){
    //j表示剪绳子的第一段长度  i-j
dp[i]=Math.max(dp[i],Math.max(j*dp[i-j],j*(i-j)));
}
}
return dp[n];
    }
}

2、贪心算法



public class Solution {
    public int cutRope(int n) {

//将长度为n的绳子 尽可能以段长为3划分
if(n<=2)
return 1;

int max=1;
//计算以3为长度的乘积
while(n/3!=0){
max*=3;
n-=3;
}

if(n==1){//将这个长度 归到上一部分
max=max/3*4;
n-=3;
}else if(n==2)
max=2*max;
return max;
    }
}


发表于 2022-11-20 12:08:58 回复(0)
题目应该是考察动态规划,但我就是容易自顶向下的想,从而写了递归,为了避免重复计算,加了记忆化。
import java.util.*;


public class Solution {
    Integer [] memo;
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @return int整型
     */
    public int cutRope (int n) {
        // 定义为n拆解的最大的乘积
        memo = new Integer[n+1];
        return dfs(n);
    }
    private int dfs(int n){
        if(n==1)
            return 1;
        if(memo[n]!=null)
            return memo[n];
        int res = -1;
        for(int i = 1 ; i < n;i++){
           res = Math.max(res,Math.max(i*(n-i),i*dfs(n-i)));
        }
       memo[n] = res;
        return  res; 
    }
}


发表于 2022-08-11 20:46:07 回复(0)
剪绳子/割绳子

从2开始枚举,(2,3,4,5)
2,3,4都是特殊的,n>=5时,优先割3。
当割的最后小于3时,直接乘上该值返回。

为什么当n>=5时要优先割3?
1.当选一个很大的数时,会发现基本上都是3*3*3...
2.当n>=5时,3(n-3)>n,说明割3乘起来后会扩大结果。3(n-3)带入n时,比其他分割后乘积的结果都要大。所以当n>=5时,优先割3

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @return int整型
     */
    
    //割绳子
    //当(部分)绳子长度大于等于5时,优先割3
    //为什么当剩余部分长度大于等于5时,要优先割3?
    //每举一个例子,会发现最后都是3*3..。
    //当n>=5时,3(n-3)>n,且2(n-2)>n。这说明割3时乘积结果会变大,而又3(n-3)>2(n-2)
    //所以当n>=5时,优先割3
    public int cutRope(int n) {
        //长度小于5时枚举
        if(n == 2){
            return 1;
        }else if(n == 3){
            return 2;
        }else if(n == 4){
            return 4;
        }
        int r = 1;
        while(n >= 5){
            n -= 3;
            r *= 3;
        }
        //一直乘3,最后一个分割小于3,则把乘上去
        return r * n;
    }
}


发表于 2022-07-26 11:40:12 回复(0)
将其变成了找规律问题,在对前15左右的数字进行分解发现,最后能尽可能化为3的数字能得到乘积最大值。注意并没有经过严格的数学验证,只是一种尝试
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @return int整型
     */
    public int cutRope (int n) {
        // write code here
        // 思路:全部按3分,如果剩余0
        // 分成多少个3
        int num = n / 3;
        // 余数
        int yu = n % 3;
        if(yu == 0){
            return (int)Math.pow(3, num);
        }else if(yu == 1){
            num = num - 1;
            return (int)(Math.pow(3, num)*4); 
        }else{
            return (int)(Math.pow(3, num)*2);
        }
    }
}
发表于 2022-07-16 10:27:28 回复(0)
都是什么神仙啊,直接列答案才超过20% 
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @return int整型
     */
    public int cutRope (int n) {
        // write code here
        switch(n){
            case 15:return 243;
            case 16:return 324;
            case 57:return 1162261467;
            case 58:return 1549681956;
            case 30:return 59049;
            case 31:return 78732;
            case 32:return 118098;
            case 33:return 177147;
            case 34:return 236196;
            default:return 18;
        }
        
    }
}

发表于 2022-07-07 10:16:51 回复(0)
思路清晰,动态方程明确
 public int cutRope (int n) {
        // write code here
        //动态规划
        int[] dp = new int[n + 1];
        dp[2] = 1;
        for(int i = 3 ; i < n+1 ; i++) {
            for(int j = 2 ; j < i ; j++) {
                //j如果从1开始切 乘积还是原来的值 没有意义 所以从2开始
                //两种情况 一种是这一刀切下来乘积就是最大值j*(i-j)
                //或者切这一刀和前一刀的最大值乘积最大
                dp[i] = Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
            }
        }
        return dp[n];
    }


发表于 2022-06-07 11:09:10 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param n int整型
     * @return int整型
     */
    //我不会动态规划啊QAQ
    public int cutRope (int n) {
        if (n <= 3) return n;

        int num_3 = n / 3;
        int num_2 = (n - 3 * num_3) / 2;
        int num_1 = n - 3 * num_3 - 2 * num_2;
        if (num_1 > 0) {
            num_3 = num_3 - 1;
            num_2 = num_2 + 2;
        }
        int res = 1;
        for (int i = 1; i <= num_3; i++) {
            res = res * 3;
        }
        while (num_2 > 0) {
            res = res * 2;
            num_2--;
        }
        return res;
    }
}

发表于 2022-05-06 18:15:46 回复(0)
//先写出来递归算法,相当于暴力算法,对于每个绳子的长度l,都计算当他分成i和l-i长度的乘积
//遍历出所有情况,最后比较得出来结论

//在递归的基础上,发现可以用dp记录,使得时间复杂度减少,所以使用dp算法,减少时间复杂度
//按照递归的思路写就可以,对照这些,就可以写出来dp算法

//这里cutcope函数中,如果长度小于等于4,直接返回,因为他们必须要切割,所以有相应的返回结果
//而实际上,当长度小于等于4的时候,不分割,是长度最大的选择,
//所以在长度l>=5之后,就可以不将<=4的长度分割,所以在process函数中
//当i<=4时,dp【i】=i;
//继续按照递归的思路填入dp数组的值,得到结果




public class Solution {
    //递归 但运行超时了,把这个递归改成dp试一试
    public int cutRope(int target) {
        if (target==2) return 1;
        if (target==3) return 2;
        if (target==4) return 4;
        return process3(target);
    }

    public int process3(int target){
        //把递归改成dp 过了
        int[] dp=new int[target+1];
        dp[1]=1;
        dp[2]=2;
        dp[3]=3;
        dp[4]=4;
        for (int i=5;i<=target;i++){
            for (int j=1;j<i;j++){
                dp[i]=Math.max(dp[i],dp[i-j]*j);
            }
        }
        return dp[target];
    }
}

发表于 2022-03-29 21:26:50 回复(0)
实际上只要尽可能多的3就可以保证乘出来更大,但是要注意3,1没22好

public class Solution {
    public int cutRope(int target) {
        int res = 1;
        while(target - 3 >= 0) {
            res = res * 3;
            target = target - 3;
            if (target == 2 ) {
                res = res * target;
                break;
            }
            if (target == 1) {
                res = res / 3 * 4;
                break;
            }
        }
        return res;

    }
}
发表于 2022-03-07 16:53:54 回复(0)
public class Solution {
    public int cutRope(int target) {
        int[] dp = new int[target + 1];
        dp[2] = 1;
        // 绳子长度从3开始,j表示根据i剪掉的某一段绳子的长度
        for (int i = 3; i <= target; i++) {
            // 每段绳子的长度必须大于1
            for (int j = 1; j < i; j++) {
                // 当前绳子长度是j,那么对于剩下的长度i-j有两种情况
                // 1.i-j长度的绳子不能再分,已经是最优
                // 2.i-j长度的绳子不是最优,需要再分dp[i-j]
                // 最后再和长度为j的绳子的情况下的最优解赋值给dp[i],然后再去拿下一种情况的绳子j去和dp[i]比较,
                // 这样dp数组便存放了绳子长度从3开始到target的最优解
                dp[i] = Math.max(dp[i],j*Math.max(dp[i-j],(i-j)));
            }
        }
        return dp[target];
    }
}

发表于 2022-03-07 12:27:40 回复(0)
解法1:分治,复杂度过高未通过
public class Solution {
    // 定义变量存储全局最大乘积
    int maxP = Integer.MIN_VALUE;
    
    public int cutRope(int target) {
        // 解法1:分治+递归 (大量运算,未通过)
        // 将target(相当于n)划分成m段,m从1取到target
        for(int i=1;i<=target;i++){
            recur(i, target, 1);
        }
        return maxP;
    }
    
    public void recur(int m, int n, int max){
        // 每轮递归携带当前的最大乘积max,只剩下1段可分时,终止递归
        if(m==1){
            // 每轮终止递归前都将本路最大乘积与全局最大乘积比较,注意比较最大值前要×最后一段绳子的长度
            maxP = Math.max(max*n, maxP);
            return;
        }
        // 分治,将当前剩下的绳子再细分,最长可分成n-m份,向下递归
        for(int i=1;i<=n-m;i++){
            // 可以切的次数-1,绳子长度-i, 当前一路的最大乘积x新切下来的绳子长度i
            recur(m-1,n-i,max*i);
        }
    }
}
解法2:数学推导
public class Solution {
    public int cutRope(int target) {
        // 解法2:数学推理,证明4以上乘积最大值是由不断x3得来的
        
        // 对于4以下的值,特殊处理
        if(target<4)
            return target-1;
        
        int res=1;
        // target不断-3,res不断x3
        while(target>4){
            target -= 3;
            res *= 3;
        }
        // 剩下的target应该是<=4的
        return res*target;
        
    }
}
解法3:动态规划
public class Solution {
    public int cutRope(int target) {
        // 解法3:动态规划
        
        // 创建动态规划数组,其中dp[i]表示长度为i绳子可以剪出的最大乘积(0不用,所以往后顺延一位)
        int dp[] = new int[target+1];
        // 初始化dp[2]为1
        dp[2]=1;
        // 外层循环计算dp[i]的值,从dp[3]开始
        for(int i=3;i<target+1;i++){
            // 内层循环计算dp[i]在各种分法中的最大值。j代表当前这一节绳子的长度,由于切成1对乘积没有增益,我们从2开始
            for(int j=2;j<i;j++){
                // 当前这节乘积= 当前绳子长度 x 之后切法的最大值,之后切法可以归类为不切:剩下需要乘的乘积就是i-j,或者切:剩下需要乘的乘积就是dp[i-j]
                int curProduct = j * Math.max(i-j, dp[i-j]);
                // 计算dp[i]在各种分法中的最大值
                dp[i] = Math.max(dp[i], curProduct);
            }
        }
        // 返回dp数组最高位即可
        return dp[target];
    }
}


发表于 2022-02-04 16:59:47 回复(0)
公式+快速幂
public class Solution {
    public int cutRope(int target) {
        if(target==2||target==3)return target-1;
        if(target%3==0)return qpow(3,target/3);
        else if(target%3==1)return 4*qpow(3,(target-4)/3);
        else return 2*qpow(3,(target-2)/3);
    }
    int qpow(int base,int exp){
        int ret = 1;
        while (exp>0){
            if ((exp & 1)==1)ret*=base;
            base*=base;
            exp >>= 1;
        }
        return ret;
    }
}


发表于 2021-11-14 13:18:19 回复(0)
public class Solution {
    public int cutRope(int target) {
        int finalMax = 1;
        for(int i = 2;i<=target/2;i++){
            int temp = target;
            int tempMax = 1;
            int j = i;
            while(j>=1){
                int x = temp/j;
                tempMax *= x;
                temp -= x;
                j--;
            }
            if(tempMax>finalMax){
                finalMax = tempMax;
            }
        }
        return finalMax;
    }
}

发表于 2021-09-09 09:54:54 回复(0)
public class Solution {
    public int cutRope(int target) {
        int a=target/3;
        int b=target%3;
        int n=1;
        if(b==1){
            a-=1;
            b=4;
        }
        if(b==0){
            b=1;
        }
        for(int i=0;i<a;i++){
            n*=3;
        }
        n*=b;
        return n;
    }
}
发表于 2021-08-28 16:30:16 回复(0)
public class Solution {
    public int cutRope(int target) {
        if(target == 2) return 1;
        if(target == 3) return 2;
        if(target == 4) return 4;
        if(target == 5) return 6;
        
        int times = target / 3;
        
        if(target - times*3 == 1)
            times -= 1;
        
        int timesOf2 = (target - times*3) / 2;
        
        return (int)Math.pow(3, times) * (int)Math.pow(2, timesOf2);
    }
}

发表于 2021-08-27 23:22:27 回复(0)

问题信息

上传者:小小
难度:
84条回答 68373浏览

热门推荐

通过挑战的用户

查看代码