c++背包九讲之01背包

一、背包九讲总述

关于动态规划问题,最典型的就是背包九讲,先理解背包九讲后再总结关于动态规划的问题。

1、01背包问题
2、完全背包问题
3、多重背包问题
4、混合背包问题
5、二维费用的背包问题
6、分组背包问题
7、背包问题求方案数
8、求背包问题的方案
9、有依赖的背包问题

二、01背包问题
01背包(ZeroOnePack): 有n件物品和一个容量为C的背包, 每种物品均只有一件,第i件物品的费用是w[i],价值是v[i]。求解将哪些物品装入背包可使价值总和最大。

*特点:*每种物品仅有一件,可以选择放或不放。
所以对于第i件物品,可以分为两种情况:放进背包与不放进背包
设V[i][j] 为只有i个物体,背包容量为j时,可获得的最大价值总和。

1、第i件选择不放进背包时:V[i][j]=V[i-1][j];
此时总价值就是只有i-1个物体,背包容量为j时,可获得的最大价值总和
2、第i件选择放进背包时:V[i][j]=V[i-1][j-w[i]]+v[i];
此时总价值就是只有i-1个物体,背包容量为j-w[i]时,可获得的最大价值总和,再加上自身的价值

我们需要的v[i][j]就是这两种情况的最大值

举例1:自上而下,从左到右生成
在这里插入图片描述
举例2:自下而上,从左到右生成
在这里插入图片描述
稍微解释一下:
1、e2这个单元格的意义是用来表示只有物品e时,有个承重为2的背包,那么这个背包的最大价值是0,因为e物品的重量是4,背包装不了。
2、对于d2单元格,表示只有物品e,d时,承重为2的背包,所能装入的最大价值,仍然是0,因为物品e,d都不是这个背包能装的。
3、对于承重为8的背包,a8=15,是怎么得出的呢?
根据01背包的状态转换方程,需要考察两个值,一个是V[i-1][j],对于这个例子来说就是b8的值9,另一个是V[i-1][j-w[i]]+v[i];而我们需要的是这两个值中的最大值。
其中:
V[i-1][j]表示我有一个承重为8的背包,当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值,对于这个例子来说就是b8的值9。
V[i-1][j-w[i]]+v[i]表示若装入第i和物体,则背包剩下j-w[i]的空间,且只有b,c,d,e四件物体可以装,于这个例子来说就是b6的值9。 再加上自身价值6,9+6=15>b8=9,故a8==15;

我们用代码实现这个例子:

#include<iostream>
#include<algorithm>

using namespace std;

//全局变量定义在堆区,自动初始化
int V[100][100];
int x[100];

int packet(int n, int C, int v[], int w[])
{
	int i = 0, j = 0;
	//此循环为核心,重点!!
	for (i = 0; i <= n; i++)
	{
		for (j = 1; j <= C; j++)
		{
			if (j < w[i])
			{
				V[i][j] = V[i - 1][j];
			}
			else
				V[i][j] = max(V[i - 1][j ], V[i - 1][j - w[i]] + v[i]);
		}
	}
	cout << V[n][C] << endl;
	//判断那些物品被选中
	for (i = n; i > 0; i--)
	{
		if (V[i - 1][C - w[i]] + v[i] >= V[i - 1][C])
		{
			x[i] = 1;
			C -= w[i];
		}
	}
	cout << "选中的物体是:";
	for (i = 1; i <= n; i++)
	{
		if (x[i] == 1)
			cout << i << " ";
	}
	cout << endl;
	return 0;
}

int main()
{
	int n;		//输入的物品个数
	int C;		//最大的容量

	int v[100] = { 0 };		//第i个物品的价值
	int w[100] = { 0 };		//第i个物品的重量
	cout << "输入物品个数" << endl;
	cin >> n;
	cout << "输入背包容量" << endl;
	cin >> C;
	cout << "输入各个物品的价值" << endl;
	for (int i = 1; i <= n; i++)
	{
		cin >> v[i];
	}
	cout << "输入各个物品的重量" << endl;
	for (int i = 1; i <= n; i++)
	{
		cin >> w[i];
	}
	packet(n, C, v, w);
	while (1);

}

在这里插入图片描述
进一步升华:
上面使用二维数组来记录每一个状态,人们追求更好的方法,即使用滚动数组来优化空间,用一维数组来实现:
二维数组实现:
V[i][j] = max(V[i - 1][j ], V[i - 1][j - w[i]] + v[i])
一维数组实现:
V[j] = max(V[j], V[j - w[i]] + v[i])

注意是逆序实现(为了保证每个物体只有一件)

在这里插入图片描述

#include<iostream>
#include<algorithm>

using namespace std;

//全局变量定义在堆区,自动初始化
int V[100];
int x[100];

int packet(int n, int C, int v[], int w[])
{
	int i = 0, j = 0;
	//此循环为核心,重点!!
	for (i = 0; i <= n; i++)
	{
		//滚动数组优化空间,逆序
		for (j = C; j > 0; j--)
		{
			if (j < w[i])
			{
				V[j] = V[j];
			}
			else
				V[j] = max(V[j], V[j - w[i]] + v[i]);
		}
	}
	cout <<"最大价值为: "<< V[C] << endl;
	cout << "被选中的物体为: ";
	for (int k = n; k > 0; k--)
	{
		if (V[C - w[k]] + v[k] >= V[C])
		{
			x[k] = 1;
			C -= w[k];
		}
	}

	for (int k = 1; k <= n; k++)
	{
		if (x[k] == 1)
			cout << k << " ";
	}

	return 0;
}

int main()
{
	int n;		//输入的物品个数
	int C;		//最大的容量

	int v[100] = { 0 };		//第i个物品的价值
	int w[100] = { 0 };		//第i个物品的重量
	cout << "输入物品个数" << endl;
	cin >> n;
	cout << "输入背包容量" << endl;
	cin >> C;
	cout << "输入各个物品的价值" << endl;
	for (int i = 1; i <= n; i++)
	{
		cin >> v[i];
	}
	cout << "输入各个物品的重量" << endl;
	for (int i = 1; i <= n; i++)
	{
		cin >> w[i];
	}
	packet(n, C, v, w);
	while (1);
}

在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
c 01背包问题是一种经典的背包问题,其中给定一个背包的容量和一组物品,每个物品有一个重量和一个价值。目标是选择物品放入背包中,使得放入的物品总重量不超过背包容量,并且总价值最大化。 采药问题是c 01背包问题的一个具体应用场景。在采药问题中,给定一个草药园和一些草药的价值和采摘时间,每种草药在一定的时间内可以采摘得到一定的价值。采药者只有有限的时间来采摘草药,他需要选择哪些草药采摘,并且使得采摘的草药的总价值最大化。 思路和解法可以参考引用和引用中提供的链接和提示。其中,引用提供了洛谷和AcWing中关于c 01背包问题的其他约束条件和实现方式的说明,引用提供了优化思路和解法的具体描述。 总结来说,c 01背包采药问题是一个经典的背包问题的具体应用,目标是在有限时间内选择草药使得总价值最大化。具体的解法可以参考引用和引用中提供的链接和提示。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [[C++]背包问题(1):洛谷 采药 01背包模型详解](https://blog.csdn.net/weixin_62712365/article/details/124640545)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [[AcWing] 423. 采药(C++实现)01背包问题](https://blog.csdn.net/weixin_43972154/article/details/124313102)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值