zoukankan      html  css  js  c++  java
  • 动态规划与贪心算法_剪绳子问题

    问题:

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

    求解:

    1.动态规划
    求一个问题的最优解(最大值或最小值),而且该问题能够分解成若干子问题,并且子问题之间还有重叠的更小的子问题,可以考虑动态规划
    (1) 分析是否能把大问题分解成小问题
    (2) 分解后的每个小问题存在最优解
    (3) 小问题的最优解组合起来能得到整个问题的最解

    2.贪心算法求解:
    每一步都可以做出一个贪婪的选择,基于这个选择,确定能够得到最优解
    1. 贪心算法在对问题求解时,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解
    2. 选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关
    3. 题目贪心策略:当n>=5时,尽可能多地剪长度为3的绳子;当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子

     

    1.首先用动态规划递归实现,动态规划实际上就是用空间效率换区时间效率的一种做法:

    
    
    public class Test {
        public static int getMax(int n){
         //要求长度n>1,所以这里返回0表示输入非法 
            if(n<2){
                return 0;
            }
         //长度为2时,要求剪下段数m>1,所以最大是1x1=1 
            if(n==2){
              return 1;
            }
         //长度为3时,要求剪下段数m>1,所以最大是1x2=2
            if(n==3) {
                return 2;
            }
            //存储长度从 0-n 的最大结果
            int[] result=new int[n+1];
            result[0]=0;
            result[1]=1;
            result[2]=2;
            result[3]=3;
            //自底向上开始求解
            int max=0;
            for(int i=4;i<=n;i++){
           //每次将最大乘积清空
                max=0;
           //因为要计算f(j)乘以f(i-j)的最大值,j超过i的一半时是重复计算,所以只需要考虑j不超过i的一半的情况
                for(int j=1;j<=i/2;j++){
             //计算f(j)乘以f(i-j)
                    int tempResult=result[j]*result[i-j];
                    if(max<tempResult) {
                        max = tempResult;
                    }
             //更新表中的f(i)=max(f(j)·f(i-j))
                    result[i]=max;
                }
            }
            max=result[n];
            return max;
        }
    
    }
     
    2.采用贪心算法得到最优解:
    
    
    public static int getMaxValue(int n){
        if(n<2) {
            return 0;
        }
       if(n==2) {
            return 1;
        }
        if(n==3) {
            return 2;
        }
        //先求出长度为3的段一共有多少段
        int countOfThree=n/3;
        //再看除了长度为3的段,还剩下多少米,如果还剩1米则表示有(n-1)个3和一个4,
        // 所以要把上一步算出来的3的个数减1,把最后的4剪成两段长度为2的绳子
        if(n-countOfThree*3==1){
            countOfThree-=1;
        }
        //当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子
        int countOfTwo=(n-countOfThree*3)/2;
        //计算所有的3的countOfThree次方,再乘以剩下2的countOfTwo次方
        return (int) ((Math.pow(3, countOfThree))*(Math.pow(2, countOfTwo)));
    }
    
    
     
  • 相关阅读:
    svg 画地图
    小议 localStorage
    .NET Core 的缓存篇之MemoryCache
    .NET Core Session的简单使用
    .NET Core 使用NLog日志记录
    .NET Core 技巧汇总篇
    .NET Core 获取自定义配置文件信息
    微信支付教程系列之公众号支付
    微信支付教程系列之扫码支付
    微信支付教程系列之现金红包
  • 原文地址:https://www.cnblogs.com/cdlyy/p/12153369.html
Copyright © 2011-2022 走看看