一:问题
01背包问题描述:一个容量为V的背包。现在有N种物品,每种只有一个物品,每种物品的体积是C1,C2,…,Cn,对应的每种的价值是W1,W2,…,Wn.。试问,在不超过背包容量的情况下,物品装入背包的最大价值?
二:分析理解
动态规划DP来解决背包问题。
先来看下它的状态,dp[ n ][ v ]表示:前n件物品中选取若干件物品放入剩余空间为v的背包中所能得到的最大价值。
状态转移方程:假如现在算到dp[ i ][ j ],现在是第i个物品,容量是j,那么对于第i个物品有两种选择,放入背包与不放入背包。
则为:dp[ i ][ j ]=max( dp[ i-1 ][ j ] , dp[ i-1 ][ j-Ci ]+Wi )。
三:代码
#include<iostream> #include<algorithm> using namespace std; #define N 6 #define V 10 //背包容量 int w[N + 1] = { 0,2,3,1,4,6,5 }; //6个物品的价值,第一个0除外 int v[N + 1] = { 0,5,6,5,1,19,7 }; //6个物品的体积,第一个0除外 int dp[N + 5][V + 5]; int main() { for (int i = 1; i <= N; i++) { for (int j = 0; j <= V; j++) { dp[i][j] = dp[i - 1][j];//假设第i个不取 if (j - v[i] >= 0 && dp[i][j] < dp[i - 1][j - v[i]] + w[i])//如果比它大,再取第i个 dp[i][j] = dp[i - 1][j - v[i]] + w[i]; } } printf("最大价值是:%d\n", dp[N][V]); return 0; }
五:优化
考虑一下是否可以对以上程序进行时间或者空间上的优化?
思考发现,时间上无法优化,但是空间是可以优化的。
我们看下状态转移方程:dp[ i ][ j ]=max( dp[ i-1 ][ j ] , dp[ i-1 ][ j-Ci ]+Wi ),当我们求解dp[ i ][ j ]的时候,只需要用到dp[ i-1 ][ j ] , dp[ i-1 ][ j-Ci ]这两个数据,那么我们完全可以使用一维数组dp[ j ]来代替dp[ i ][ j ]啊。
这里还需要注意的是,原先程序的两层循环 i 和 j 都是从0开始的,但是若是要用一维数组,第二层循环 j 就要从V开始往前推导,为什么?
假如现在我们 j 从0开始往后推,dp[ j ]表示在当前 i 循环下容量为 j 的最大价值,dp[ j ]=max( dp[ j ],dp[ j-Ci]]+Wi] ),好了,很容易发现dp[ j-Ci ]应该和dp[ i-1 ][ j-Ci ]相等,但是其实不然,这里的dp[ j-Ci ]已经是等于dp[ i ][ j-Ci ]了。好了,还是看下代码吧。
六:优化后的代码
#include<iostream> #include<algorithm> using namespace std; #define N 6 #define V 10 //背包容量 int w[N + 1] = { 0,2,3,1,4,6,5 }; //6个物品的价值,第一个0除外 int v[N + 1] = { 0,5,6,5,1,19,7 }; //6个物品的体积,第一个0除外 int dp[V + 5]; int main() { for (int i = 1; i <= N; i++) for (int j = V; j >= v[i]; j--) dp[j] = max(dp[j], dp[j - v[i]] + w[i]); printf("最大价值是:%d\n", dp[V]); return 0; }
返回背包系列目录--->背包系列目录