动态规划:
动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。 [1] 动态规划算法的基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。
通常 基于 一个递推公式 及一个或多个初始状态。当 前子问题的解将由上一次 子问题的解推出。
钢条问题:
给定一个长度为n英寸的钢条和一个价格表pi(i=1,2,3,...n),求能够使销售收益rn最大的切割方案
长度 i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
价格p[i] | 1 | 5 | 8 | 9 | 10 | 17 | 17 | 20 | 24 | 30 |
考虑n=4的时候
假如一个最优解把n段切成了k段(1<=k<=n),那么最优切割方案:
i及下标表示第i段的长度,n为钢条的总长度。
最大收益:
p及下标表示第i段的收益,r为钢条的总收益。
接下来对这个问题进行求解,我们先用普通的递归方法求解:
我们从钢条的左边切下长度为i的一段,只对右边剩下长度为n-i的一段继续进行切割,对左边的不再切割。
这样,当第一段长度为n的时候,收益为p[n],剩余长度为0,收益为0(这也是递归的基本问题),对应的总收益为p[n]。
当第一段长度为i的时候,收益为p[i],剩余长度为n-i,对应的总收益为p[i]加上剩余的n-i段再进行当第一段长度为i的时候,收益为p[i],剩余长度为n-i-i,....直到剩余长度为0,收益为0。
所以递归方程式为:
pi就是就是p[i],可以看出每次都要进行从1到n的遍历。
public static int UpDown2(int n, int[] p)
{
if (n == 0) return 0;
int MaxPrice=0;
for (int i = 1; i <=n; i++)
{
int temp = p[i] + UpDown2(n - i, p);
if (temp>MaxPrice)
{
MaxPrice = temp;
}
}
return MaxPrice;
}
这个方法效率 是指数型的增加,r[9]和r[8] 都分解了r[7]
可以 加个 数组 来保存上次的值;
每次执行 都去判断是否存在。
动态规划:
①自顶向下的备忘录法
static int UpDown(int n,int[] p,int[] result)
{
if (n==0){return 0;}
int max = 0;
if (result[n]!=0){return result[n];}
for (int i = 1; i <=n ; i++)//i<n+1 最大值 就是n
{ // 长度为n的 最大 收益
int temp= p[i]+UpDown(n-i,p,result);
if (temp>max){ max = temp;}
}
result[n] = max; // 保存 下n的 结果
return max;
}
上面的方法思想还不算是 动态规划思想
下面介绍另一种
②自底向上
static int UpDown2(int n, int[] p, int[] result)
{
for (int i = 1; i <= n; i++)
{
int tempMax = -1;
for (int j = 1; j <= i; j++)// 遍历 1到 i 寻找最大子数组
{
int temp = p[j] + result[i - j];
if (temp > tempMax)
{
tempMax = temp;
}
}
result[i] = tempMax;
}
return result[n];
}