慨念
动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。
动态规划关键
1、最优子结构
2、边界
3、状态转换方程式
例子
从斐波那契数列的式子出发
F(1)=1 当n=1时(边界)
F(2)=1 当n=2时(边界)
F(n)=F(n-1)+F(n-2) 当n>3时(状态转换方程式)
但是会有以下问题,看下图
时间复杂度很高,是O(2^n),树中很多的要求的值重复了
颜色相同的式子重复了,那我们可以利用一个map中的key不重复来存储F(n),value来存储其值,这样时间复杂度就会减少到O(n),(代码如下)但是空间会消耗很大,再分析一下
看回来方程,F(n)=F(n-1)+F(n-2) 想要推导出想要的值,只要知道前两个值就OK了
故代码:
int dynamic(int n){
if (n<0){return 0;}
if (n==1){return 1;}
if (n==2){return 1;}
int i=1;
int j=1;
int temp=0;
for (int a=3;a<=n;a++){
temp=i+j;
i=j;
j=temp;
}
return temp;
}
例子二———数组中不相邻元素相加最大
例如如下数组
int arr[]={3,1,3,5}
有如下条件:
1、相加元素不能相邻
2、得出元素最大值
分析其中最优子结构:当我选择arr[3]时,该数组的最优最大值是F(3)=arr[3]+F(1),否则是 F(2)
也就是说,可以总结出这样的规律来
最优解是 MAX(arr[3]+F(1),F(2))
以此类推得出最优子结构:
F(3)=MAX(arr[3]+F(1),F(2))
然后,边界值也很容易出来就是F(0),F(1),容易得出F(0)=arr[0],F(1)=MAX(arr[1],arr[0])
得出状态转换方程:
F(0)=arr[0] n=0时
F(1)=MAX(arr[1],arr[0]) n=1时
F(n)=MAX(F(n-2)+arr[n], F(n-1)) n>=2时
故代码为:
int dynamic_dp(int []arr){
int [] results=new int[arr.length];
results[0]=arr[0];
results[1]=Math.max(arr[0],arr[1]);
for (int i=2;i<results.length;i++){
int a=results[i-1];
int b=results[i-2]+arr[i];
results[i]=Math.max(a,b);
}
return results[arr.length-1];
}