背包系列第一篇----01背包(求解最大价值)

一:问题

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

四:数据测试

背包系列第一篇----01背包(求解最大价值)_第1张图片

五:优化

考虑一下是否可以对以上程序进行时间或者空间上的优化?

思考发现,时间上无法优化,但是空间是可以优化的。

我们看下状态转移方程: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;
}


返回背包系列目录--->背包系列目录




你可能感兴趣的:(C++,算法,dp,背包问题,01背包)