动态规划和分治方法相似,都是通过组合子问题的解来求解原问题的解。分治方法是将问题分解为相互独立的子
问题,递归地求解这些子问题,然后求原问题的解。与之不同的是,动态规划应用于子问题重叠的情形,即子问题的解依赖于子子问题的求解。在这种情形下,分治方法会做出许多不必要的工作,它会反复地去求解公共子问题。而动态规划对每个子子问题只求解一次,将其解记录在一个表格中,从而无需每次求解一个子子问题时都重新计算,避免了这种不必要的工作。
动态规划通常用来求解最优化问题。这类问题通常具多组解,对于每组解,都有一个值,我们希望求出最优值(
最小值或最大值)的解。我们称这样的解为一个最优解,一个问题可能会存在多个最优解。我们通常按照如下步骤来设计一个动态规划:
1、刻画一个最优解的结构特征;
2、递归地定义最优解得值;
3、计算最优解的值,通常采用自底向上的方法;
4、利用计算出的信息构造一个最优解。
步骤1~3是动态规划求解问题的基础。如果我们仅需要最优解得一个值,则可以忽略步骤4。如果要求解一组最
优解则在步骤3要维护一些额外的信息来,以便构造一个最优解。
2、使用动态规划求解钢条切割问题
下:问题描述:给定长度为n英寸的钢条和一张价格表pi(i=1,2,...n),求切割钢条的方案,使得收益rn最大。价格表如
例如当n=4时,那么切割方案为共有8种(因为在距离钢条左端i(i=1,2,3....,n-1)英寸处我们可以选择切割或不切
割),分别为:4(收益为9美元)、1+3(收益为9美元)、2+2(收益为10美元)、3+1(收益为9美元)、1+1+2(收益为7美元)、1+2+1(收益为7美元)、2+1+1(收益为7美元)、1+1+1+1(收益为4美元)。因此为了获得最大收益,切割方式为2+2,即把钢条切割成两段2英寸长度。
为了求解规模为n的原问题,我们先求解形式完全一样,但规模更小的子问题。即当完成首次切割后,我们将两
段钢条看成两个独立的钢条切割问题实例。我们通过组合两个相关子问题的最优解,并在所有可能的两种方案切割中选取组合收益最大者,构成原问题的最优解。我们称钢条切割问题满足最优子结构性质:问题的最优解有相关的两个子问题的最优解组合而成,而这些子问题可以独立求解。
度为i的一段,只对右边剩下的n-i的一段继续进行切割,对左边的一段不再进行切割。即问题的分解的方式为:将长度为n的钢条分解为左边开始的一段,以及剩余部分继续分解的一段。于是可以得到公式:除了上述求解方法外,钢条切割问题还存在一种相似的但更为简单的递归求解方法:我们将钢条从左边切割下长
我们采用自底向上的方法求解,代码如下:
void botom_up(int *p, int n)
{
int max = 0;
int i, j;
int *r = (int *)malloc(sizeof(int)*n);//用来保存子问题的最优解
r[0] = 0;
for (i = 1; i <= n;i++)
{
max = 0;
for (j = 1; j <= i;j++)
{
if ((p[j] + r[i - j]) > max)
max = p[j] + r[i - j];
}
r[i] = max;
}
}