算法-动态规划之基础(一)

 概念:

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));
	}
}
















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值