概念:
1,动态规划是运筹学中用于求解决策过程中的最优化数学方法。它是使用多阶段决策过程最优的通用方法。它是应用数学中用于解决某类最优化问题的重要工具。
2,动态规划可以将问题分为多个重叠的子问题,我们只需求解一次每个较小的子问题保存起来(空间换时间的概念),由重叠的子问题逐步决策,构造较大问题的解。
同时,我们从多个常见的问题中慢慢的理解动态规划算法;
加权工作调度问题:
已知:1,工作J在时刻Sj开始,在时刻Fj结束,并且有权重Vj;
2,两个工作之间不能有重叠部分;
问题:如何找到最大的权重子集,并且保证相互之间不相重叠。
步骤1,我们必须找到子问题
1,现在我们按结束时间的先后来排序,(实际上,已经排序好了)
2,定义p(j)为工作j能够与工作i(i<j)同时工作的最大的工作数量;因为我们有
p(1)=0,p(2)=0,p(3)=0,p(4)=1(工作1),p(5)=0,p(6)=2(工作1与2),p(7)=3(工作1,2与3),p(8)=5(工作1,2,3,4与5);
步骤2:我们定义opt(j)作为最理想的工作加权值,由子集工作{1,2,3....j}组成,因此我们有式子OPT(j)=max(Vj+opt(Pj),opt(j-1)).
那么我们得到的分析如下图:
伪代码如下:(时间复杂度O(n),空间复杂度O(n))
Input:n,s1......sn,f1......fn,v1.....vn
Sort jobs by finish times so that f1<=f2<=....<=fn
Compute p(1),p(2),....,p(n)
for j=1 to n
M(j)=empty;-------------->global array
M[0]=0
compute-opt(n){
if(M[n] is empty)
M[n]=max(vn+ compute-opt(p(n)), compute-opt(n-1))
return M[n];
}
java代码如下:
public class JobAttemper {
//第一位没有用,只是为了方便理解,下标与工作j匹配;
//加权的字数暂时随意定义
static int[] weight={0,3,2,5,4,2,6,2,1};
//这个p(j)是根据图表计算出来的
static int[] p={0,0,0,0,1,0,2,3,5};
//用来保存子问题的值
static int[] Memory={0,0,0,0,0,0,0,0,0};
private int compute_opt(int n){
if(Memory[n] != 0){
return Memory[n];
}
if(n == 0){
return 0;
}
Memory[n] = Math.max(weight[n]+compute_opt(p[n]), compute_opt(n-1));
return Memory[n];
}
public int getOpt(int n){
Arrays.fill(Memory, 0);
return compute_opt(n);
}
}
另一个问题:背包问题
问题:有5个东西和一个背包,背包能装下的最大的重量是w=11,每个东西有不同的价值;怎么样选取这5中物品,使得背包装下的东西价值最大;(物品已经按重量排序好了,如下所示)
分析:如果像上一道题那样用OPT(j)来表示比j轻的所有子集的最优解,但是这样的话,就不存在没有重叠的子集;
所以,我们用OPT(j,w)来表示在重量为w下所有的子集的最优解,那么我们会得到重叠的子集;
于是,我们有如下的式子:
伪代码如下:
input :n, W1......Wn,V1....Vn
Initialize M[0,W]=0 for each w=0,1.....w
for i=1,2........n
for w=0,.......W
if(Wi>W)
M[i,w]=M[i-1,w]
else
M[i,w]=max{M[i-1,w],Vi+M[i-1,w-wi]}
return M[n,W]
空间复杂度O(nw),时间复杂度O(nw)(其实就是填满表格)
java代码如下:
public class bagProblem {
//记录子问题的表格
private int[][] Memory;
//记录物品的信息
private int[] ItemV = {0,1,6,18,22,28};
private int[] ItemW = {0,1,2,5,6,7};
private int Compute_opt(int n,int weight){
if(Memory[n][weight] != 0){
return Memory[n][weight];
}
if(n == 0 || weight == 0){
return 0;
}
if(ItemW[n] > weight){
Memory[n][weight] = Compute_opt(n-1,weight);
return Memory[n][weight] ;
}else{
Memory[n][weight] = Math.max(Compute_opt(n-1,weight), ItemV[n]+Compute_opt(n-1,weight-ItemW[n]));
return Memory[n][weight];
}
}
public int getOPT(int n,int weight){
Memory = new int[n+1][weight+1];
for(int i=0;i<n+1;i++){
Arrays.fill(Memory[i], 0);
}
return Compute_opt(n,weight);
}
public static void main(String[] args) {
System.out.print(new bagProblem().getOPT(5, 11));
}
}