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

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

价格表:

长度i12345678910
价格p1589101717202430


经过分析,因为在距离钢条左端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];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值