背包问题

205 阅读3分钟

1、0/1背包问题 给定n种物品和一个容量为C的背包,物品i的重量是wi,其价值为vi。

问:应该如何选择装入背包的物品,使得装入背包中的物品的总价值最大?

问题分析:面对每个物品,我们只有选择拿取或者不拿两种选择,不能选择装入某物品的一部分,也不能装入同一物品多次。

我们声明先一个大小为f[n][c]的二 维数组,f[i][j]表示在面对第i件物品,且背包容量为j时所能获得的最大价值。

例如这样一个问题:

【题目描述】

一个旅行者有一个最多能装M公斤的背包,现在有n件物品,它们的重量分别是W1, W2, ...Wn它们的价值分别为C1,C2....Cn ,求旅行者能获得最大总价值。

【输入】

第一行:两个整数, M(背包容量, M≤200)和N(物品数量,N≤30) ; 第2..N+ 1行;每行二个整数Wi,Ci,表示每个物品的重量和价值。

【输出】

仅一行,一个数,表示最大总价值。

【输入样例】

10 4 2 1 3 3 4 5 7 9 【输出样例】

12 设置一个dp[i][j]数组。i表示的是物品,j表示容量,dp[i][j]表示价值。

dp[1][0]则表示容量为0,拿第1个物品时,价值是多少。

......

dp[1][M]表示容量为M,拿第1个物品时,价值是多少。

.....

dp[N][M]表示容量为M,拿第N个物品时,价值是多少。

画表查看

重量W[i]

价值C[i]

                                                    背包容量(一个是10)j

注①:第0个物品,无论放进多大的背包,价值都为0;

注②:第1个物品(重量为2,价值为1),只能放到背包容量大于等于2的背包;

注③:这一行的第一个数据1,背包容量为2,不足以放进第二件物品。只能不拿,这个1是上一个物品拿的价值,根据后无效原则,可以不管。j < w[i](当前物品容量大于背包容量),不足以放下,只能不拿。dp[i][j] = dp[i-1][j](上一种物品的价值);

这一行的第二个数据3,根据价值最大原则,拿的是第二件物品,价值为3;j > w[i](当前物品容量小于背包容量);

如果不拿,上一物品的价值:dp[i][j] = dp[i-1][j] = 1;如果拿了,容量应该减去当前的容量,并且价值加上当前价值。dp[i][j] = dp[i-1][j - w[i]] + c[i] = dp[1][0]+3 = 0 + 3 = 3;然后取较大值。状态转移方程式dp[i][j] = max(dp[i-1][j],dp[i-1][j - w[i]] + c[i]);

这一行的第三个数据3,dp[i][j] = max(dp[i-1][j],dp[i-1][j - w[i]] + c[i]);dp[i][j] = max(dp[2][4],dp[2][4-3] + 3) = max(3,0+3) = 3

......

//重点代码 if(j < w[i]) { dp[i][j] = dp[i-1][j]; } else { dp[i][j] = max(dp[i-1][j],dp[i-1][j - w[i]] + c[i]); } 完整代码

#include #include using namespace std;

//01背包问题

int dp[35][205];/dp[i][j]数组/ int w[35]; /重量数组/ int c[35]; /价值数组/

int main(int argc, char* argv[]) { int m, n; //m是背包重量,n是物品数量 cin >> m >> n; //读入数据 for (int i = 1; i <= n; i++) { cin >> w[i] >> c[i]; }

//做递推
for (int i = 1; i <= n; i++)
{
	for (int j = 1; j <= m; j++)
	{
		//放不下
		if (j < w[i])
		{
			dp[i][j] = dp[i - 1][j];
		}
		else
		{
			dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + c[i]);
		}
	}
}

//输出dp表
for (int i = 0; i <= n; i++)
{
	for (int j = 0; j <= m; j++)
	{
		cout << dp[i][j] << "\t";
	}
	cout << endl;
}
//只输出最终结果
cout << dp[n][m] << endl;
system("pause");
return 0;