适用于动态规划解决的问题所具有的特点:
1、求得一个问题的最优解
2、整体问题的最优解依赖于子问题的最优解
3、把大问题划分为若干小问题,这些小问题还有相互重叠的更小的子问题
4、问题可以自上而下分析,要从下而上求解。
题目一:
一段长为n的绳子,把绳子剪为m段(m,n都是整数,n>1 并且 m>1),每段绳子的长度记为 K0,K1,...,Km。请问 K0*K1*...*Km的最大乘积是多少(m不确定)? 例如:长为8的绳子切为2,3,3这三段,得到最大为18。
分析:
这是个动态规划问题,定义 f(n)为长度n的绳子剪为若干段乘积的最大值。在剪第一刀时有 n-1中结果,也就是说剪出来的绳子可能是1,2,3,4,...5,6,n-1 这些种可能长度。f(2)最大值为 1x1=1, f(3) = 1x2 = 2 > 1x1x1。
此问题的递推公式为: f(n) = max( f(i)*f(n-i) ) 方程说明:长为 n的绳子切第一刀,切为两部分,则第一刀下去就有总体的最长长度;再切第二刀...;直到绳子长为 1时,则再切一刀,最大乘积为0
代码实现:
int maxAfterCutting(int length)
{
if (length < 2)
return 0;
if (length == 2)
return 1;
if (length == 3)
return 2;
int *products = new int[length + 1]; //保存4~length 各个绳子长度情况下,乘积的最大值;多申请一个节点,则products[length]保存绳子长度为length的乘积最大值
//绳子长为0~3的情况已经在上述处理过,所以这4个位置比较特殊,为4个辅助位置
//当长度为4的绳子,切为(1和3)两段时,值就是1x3;切为(2和2)两段时,值就是2x2,这4个初始值刚好满足需求
products[0] = 0; //这个值用不到,可以不初始化;因为j<=i/2,则i-j 永远不可能等于0
products[1] = 1;
products[2] = 2;
products[3] = 3;
int max = 0;
for (int i = 4; i <= length; i++) //绳子长为 0~3 的情况在上诉的三个 if 中已经求得,程序从绳子长为4开始求解
{
//求解绳子长度为 i的最大值,f(n) = max( f(t)*f(n-t) )
max = 0; //默认各个长度对应的乘积初始都是0
for (int j = 1; j <= i / 2; j++) //j == i/2 时说明是在绳子中间切的,则此边界位置的两边计算一遍就好了
{
int product = products[j] * products[i - j]; //j 和 i-j 两段
if (max < product) //产生了更大的值,就替换掉max
max = product;
products[i] = max;
}
}
max = products[length];
delete[] products;
return max;
}
上述代码执行的一个手动过程,方便理解代码: