初学动态规划--01背包

动态规划的算法思想应用是十分广泛的,是非常常用的一种算法。

给出动态规划的抽象描述:

一个系统,有若干个状态,每个状态下有若干个操作,称为决策,决策会改变系统状态。决策会带来收益(正数)和费用(负数)。在初始状态下,求最终状态下最大收益。在每个阶段,选择一些决策,状态随之改变。收益只取决于当前状态和决策(无后效性)。当系统到达终点状态时,总收益最大(或费用最小)。总收益一般指各个阶段收益的总和。

动态规划的特点是:子问题大量重叠

应对:打表避免重复计算(牺牲空间换取时间)


说到这里对于DP我们的理解肯定还是抽象的,所以来点具体的例子作以说明,对于动态规划初学的例子,我们就来谈谈01背包

给出01背包的题目描述:

输入商品数目N,接着输入N个商品的重量和价值,输入一个限定重量,问在这一重量内,能达到的最大价值是多少?

我们可以分析一下,每准备放入一个物品的时候我们需要判断此时还能否放的下,如果可以放下,放下这个的情况和不放这个的情况哪个可以获得更大的收益(即在一定的重量内可以获得最大的价值),经过递归我们读出最后的数据。

给出根据算法思想写出的代码:

int rec(int i, int j){
	int res;
	if(i == n){
		res = 0;
	}
	else if(j < w[i]){
		res = rec(i + 1, j);
	}
	else{
		res = max(rec(i + 1, j) , rec(i + 1, j - w[i]) + v[i]);
	}
	return res;
}

我们可以简单研究一下该算法的时间复杂度,我们发现,这个代码写出来的方法需要执行很多重复的情况.举例来说,给出一下输入数据:

4

2 3

1 2

3 4

2 2

5

那么在输入时就有重复的(3,2)状态,出现在前两个递归不取物品,第三个递归取物品时与第一个递归取物品,第二个递归继续取物品,这时无法取第三个物品,所以组成(3,2)状态.所以这种方法的搜索深度是n,而且每一层的搜索搜需要两次分支,最坏需要O(2^N),当N比较大的时候就可能超市了

那么为了解决这种问题我们该怎么办呢,就用到我们上面抽象描述中给出的方法,也就是打表,以消耗空间的方式来换取时间.我们需要一个二维矩阵dp[MAX_N][MAX_N],借用这个矩阵对每个状态进行记忆,如果再遇到这种状态时,立即返回这种状态的值即可,就没必要继续递归下去.给出代码:

int rec(int i, int j){
	int res;
	if( dp[i][j] ){
		return dp[i][j];                                                                  //如果该状态记忆矩阵中有记录的话,我们将此返回
	}
	if(i == n)
		res = 0;
	else if(j < w[i])
		res = rec(i + 1, j);
	else{
		res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]);
	}
	return dp[i][j] = res;                                                                 //对该状态进行记忆
}

我们发现这张对于同样的参数,只会在第一次被调用时需要执行递归部分,第二次后直接返回,参数的组合不过N*W种,而函数只调用两次递归,所以只需要O(N*W)

当然我们容易知道,dp的形式有很多很多,我们可以通过二维数组直接对我们的dp数组进行填表,我们将数组初始化后,从下往上填充,然后我们可以知道,最后第0行的第w行为放入最大价值的情况


我们常说的递归(DP)就是这样:

int solve(){
	int i, j;
	for(i = n - 1; i >= 0; i --){
		for(j = 0; j <= W; j ++){
			if(j < w[i]){
				dp[i][j] = 0;
			}
			else {
				dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i]);
			}
		}
	}
}
我们一般在做DP时需要给出动态转移方程:

如上面的动态转移方程我们可以写作:

dp[n][j] = 0;

dp[i][j] = ①dp[i + 1][j] (j < w[i])

      ②max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i])

动态转移方程是我们写出代码的思想基础.

posted @ 2015-06-05 22:19  ChiLuManXi  阅读(261)  评论(0编辑  收藏  举报