算法学习(动态规划 一)钢条切割

来源:互联网 发布:软件开发认证 编辑:程序博客网 时间:2024/06/09 21:44

给定一段长度为n的钢条和一个价格表,求切割钢条方案,使得销售收益最大:

价格表:

长度i 1 2 3 4 5 6 7 8 9 10 价格p 1 5 8 9 10 17 17 20 24 30


经过分析,因为在距离钢条左端i(i = 1, 2, 3…n)处,总是可以选择切割或者不切割,因此可得,其共有

2n1
种切割方案,以下是使用自顶向下递归实现的代码

/** 该方法使用穷举统计,将所有的情况全部统计得出最优解 @param prices 给定的价目数组 @param index 获取当前位置的最优解 @return 返回给定位置的最优解 */int exhaustionStatistics (int *prices, int index){    //TODO: 1.当所选位置为0时,价值也为0    if (index == 0)        return 0;    //TODO: 2.通过递归调用来获取最优解    int result = -INT_MAX;    for (int i = 1; i <= index; i++)    {        int addPrice = prices[i - 1] + exhaustionStatistics(prices, index - i);        result = result > addPrice ? result : addPrice;    }    return result;}

经过测试,如果输入的规模变大,则会导致程序运行时间变得很长,这是因为此函数考察了所有的可能,因此,规模的增大是的运行时间呈指数增长

为了节省更多的时间,可以使用动态规划的方法,一种是带备忘的自顶向下法,仍然按照递归实现,但是会保存每个子问题的解,当求解时,如果已经保存过此解,则直接返回:

/** 求解最优解问题 @param prices 给定的价目数组 @param index 获取当前长度的最优解 @return 返回最优解 */int Advanced::memoizedCutPod(int *prices, int index){    //TODO: 1.创建一个备忘录数组,用来保存已经求解出的各个长度最优解    int memo[index];    for (int i = 0; i < index; i++)        memo[i] = -INT_MAX;    return memoizedCutPodAux(prices, index, memo);}/** 根据备忘录自顶向下来求解最优解 @param prices 给定的价目数组 @param index 获取当前长度最优解 @param memo 保存各个长度最优解的备忘录 @return 返回最优解 */int Advanced::memoizedCutPodAux(int *prices, int index, int *memo){    //TODO: 1.备忘录当前位置中存在数据的话,直接返回    if (memo[index - 1] >= 0)        return memo[index - 1];    //TODO: 2.如果当前位置为0,则最优解为0    int result;    if (index == 0)        result = 0;    else    {        //TODO: 3.在其他位置时,首先设置最小值        result = -INT_MAX;        for (int i = 1; i <= index; i++)        {            //TODO: 4.递归求解出最优解            int addPrice = prices[i - 1] + exhaustionStatistics(prices, index - i);            result = result > addPrice ? result : addPrice;        }    }    //TODO: 5.求出后记录在备忘录中    memo[index - 1] = result;    return result;}

另一种是自底向上法,任何子问题的求解都依赖于更小的子问题,按照规模排序,当求解某个子问题时,它所依赖的更小的子问题已经求解完毕,结果已经保存:

/** 自底向上求解最优解 @param prices 给定的价目数组 @param index 获取当前长度的最优解 @return 返回最优解 */int Advanced::bottomUpCutRod(int *prices, int index){    //TODO: 1.创建一个数组用来保存各个位置的最优解,将0的位置的值设置为0,意为0的长度的价格为0    int memo[index + 1];    memo[0] = 0;    //TODO: 2.遍历求取当前长度的最优解    for (int j = 1; j <= index; j++)    {        int result = -INT_MAX;        for (int i = 1; i <= j; i++)        {            //TODO: 3.从保存的数组中获取最优解            int addPrice = prices[i - 1] + memo[j - i];            result = result > addPrice ? result : addPrice;        }        //TODO: 4.将最优解保存入数组        memo[j] = result;    }    return memo[index];}
原创粉丝点击