背包问题之有依赖的背包(包含模板)

本文深入解析了有依赖的背包问题,以NOIP金明的预算方案为例,阐述了主件与附件的购买策略。通过分组讨论,提出了处理有依赖背包问题的有效算法,并分享了一个适用的代码模板。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有依赖的背包最好理解的题就是NOIP的金明的预算方案,其每个物品有主件和附件,附件必须在主件已经购买了的请款下才能购买,这里牵扯到有依赖的背包的一个问题,将这些进行分组之后就有多种情况即:不能购买主件,只能购买主件,能购买主件和多个附件,这些情况组成了多个可能的情况,
所以这种情况可以先将一个组当中的附件进行一次01背包得到其背包容量为0~V-w[i]时的所有可能情况,然后将整个组当成一个分组背包的一组看待,即此时的组里只需要选择一个可能性即可

我总结了下打出了一个模板,能简单包含这种题型,尤其时像金明的预算方案这样的题稍加修改就能通过:
模板奉上:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace  std;
//简易模板适用于被依赖的物品不能再成为别的物品的附件
struct node
{
	long long w, v;
}a[1005];
int  d[1005];
vector<node>group[1005];
int n, m;
long long dp[1005];
void DP(vector<node>d)
{
	if (d.size() > 1)//有附件
	{
		int k = m - d[0].w;//除了主件剩下的q空间
		long long  *st;
		st = new long long[k];
		memset(st, 0, sizeof st);
		for (int i = 1; i < d.size(); i++)//将附件进行组合,组合成多种可能
		{
			for (int j = k; j >= d[i].w; j++)
				st[j] = max(st[j], st[j - d[i].w] + d[i].v);
		}
		for (int i = m; i >= 0; i--)//剩下的钱,作为分组背包计算
		{
			if (i >= d[0].w)//能买主件
			{
				for (int j = 0; j <= k; j++)
				{
					if (i >= d[0].w + j)
						dp[i] = max(dp[i], dp[i - d[0].w - j] + d[0].v + st[j]);
				}
			}
		}
	}
	else
	{
		for (int i = m; i >= d[0].w; i--)
			dp[i] = max(dp[i], dp[i - d[0].w] + d[0].v);
	}



}

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i].w >> a[i].v >> d[i];
		if (d[i] == 0)//主件
			group[i].push_back(a[i]);
	}

	for (int i = 1; i <= n; i++)
		if (d[i] != 0)//附件
			group[d[i]].push_back(a[i]);//进行分组

	for (int i = 1; i <= 1000; i++)
	{
		if (group[i].size() != 0)//是一个组
		{
			DP(group[i]);//每个大组进行一次有依赖的背包
		}
	}
	cout << dp[m] << endl;
	system("pause");
	return 0;
}

后续会更新一种已经作为被依赖主件又是别的主件的附件的情况,还有树状DP的模板,神犇轻喷,写的不是很好,请耐心多看两遍。

### 回答1: C 01 背包问题是一种经典的动态规划问题。它的基本思想是:给定一个容量为 C 的背包和 N 个物品,每个物品都有自己的体积和价值,求在满足背包容量限制的前提下,能够装入背包中的物品的最大价值总和。 解决该问题的常用模板为: 1. 定义状态:定义 dp[i][j] 表示考虑前 i 个物品,容量为 j 的背包能够装入物品的最大价值总和。 2. 状态计算:根据背包的容量限制和物品的体积和价值,使用递推公式进行状态转移。 - dp[i][j] = max(dp[i-1][j], dp[i-1][j-v[i]] + w[i]) 其中,v[i] 和 w[i] 分别表示第 i 个物品的体积和价值。 3. 边界:考虑边界条件,dp[0][j]=0,dp[i][0]=0。 4. 计算结果:遍历整个 dp 数组,找到一个使得 dp[N][j] 最大的 j 值,即为答案。 ### 回答2: 01背包问题是一个经典的动态规划问题,主要用于求解在给定的一组物品中,选择装入背包中以达到背包容量最大化的问题。 解决01背包问题一般采用动态规划的方法。首先定义一个二维数组dp,其中dp[i][j]表示在前i个物品中,背包容量为j时的最大价值。初始化dp数组的第一行和第一列为0,表示背包容量为0时或者没有物品可选时,最大价值均为0。 然后,利用动态规划的思想,逐个考虑每种不同的物品,并计算不同背包容量下的最大价值。具体步骤如下: 1. 遍历每个物品i,从1到n: 对于每个物品i,再从背包容量j,从1到m: 2. 如果当前物品i的重量小于等于当前背包容量j,即w[i] <= j: 则可以选择将当前物品i装入背包,计算装入该物品后的最大价值: dp[i][j] = max(dp[i-1][j-w[i]] + v[i], dp[i-1][j]) 其中,dp[i-1][j-w[i]]表示装入物品i之前的最大价值,加上当前物品i的价值v[i]; dp[i-1][j]表示不装入物品i时的最大价值。 3. 否则,当前物品i的重量大于当前背包容量j,无法装入物品i: 则最大价值为不装入物品i时的最大价值: dp[i][j] = dp[i-1][j] 最终,dp[n][m]即为前n个物品中,在背包容量为m时的最大价值。通过动态规划算法得到的dp表可以帮助我们解决01背包问题,找到最优解。 ### 回答3: 01背包问题是一个经典的动态规划问题,常用于解决选择一定数量的物品装入背包的最大价值问题。这个问题可以描述为:有一个背包,它的容量为C;有N个物品,每个物品的重量分别为w1,w2,...,wn,价值分别为v1,v2,...,vn。要求选择一些物品装入背包,使得装入的物品重量总和不超过C,并且价值总和最大。 解决这个问题的动态规划算法可以用一个二维数组dp来表示状态,其中dp[i][j]表示在前i个物品中选择一些物品,使得它们的重量总和不超过j的情况下的最大价值。可以利用以下递推公式来更新dp数组: 若j >= wi,则dp[i][j] = max(dp[i-1][j], dp[i-1][j-wi] + vi) 否则,dp[i][j] = dp[i-1][j] 其中wi为第i个物品的重量,vi为第i个物品的价值。从状态转移方程可以看出,dp[i][j]的值依赖于dp[i-1][j]和dp[i-1][j-wi],即在i-1个物品中选择一些物品时的状态。 最终,dp[N][C]就表示在N个物品中选择一些物品放入容量为C的背包时的最大价值。 实现这个动态规划算法时,可以使用一个二维数组dp来保存状态,并使用两个嵌套循环遍历物品和不同的背包容量,通过比较选择不同的物品和背包容量来更新dp数组。 这就是01背包问题模板。通过动态规划算法可以高效地解决这个问题,并得到最优的选择方案,以及最大的价值。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值