给定一段长度为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)处,总是可以选择切割或者不切割,因此可得,其共有
2n−1
种切割方案,以下是使用自顶向下递归实现的代码
/**
该方法使用穷举统计,将所有的情况全部统计得出最优解
@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];
}