P1064 金明的预算方案 有依赖的背包

这篇文章讲述了如何解决一个关于物品价值计算的问题,涉及m个物品和n的钱,物品间有价格、重要度和依赖关系。通过构建数据结构和使用动态规划方法,求解在满足依赖条件下,如何选择物品以最大化价值。
摘要由CSDN通过智能技术生成

d

[NOIP2006 提高组] 金明的预算方案 - 洛谷

参考了一些解题终于写出来了

有用的数据:m个物品,n的钱。每个物品的价格,重要度,附属哪个物品;

例如物品1:100 5 0表示这个物品价格100,根据题意:价值等于价格*重要度,自己是大哥

所以物品1可以看作重量是100,价值是500

物品2:50 2 1表示他的大哥是1,如果你想买物品2,就必须先买物品1,这就是依赖.

并且 一个物品最多有两个老弟

思路

显然,对于任意一个商品,我们可以选择买和不买,如果选择买,就会有几个分支关于买不买这件商品的附属品

难点

个人认为是这道题的数据处理

开这样的数组 item_M_v存放主件的价格(重量/体积),item_M_p用来存放主件的价值

int item_M_v[N];
int item_M_p[N];
int item_S_v[N][3];
//item_S_v[i][0]表示主件i的复件个数
//item_S_v[I][1]表示复件1号的信息
//item_S_v[I][2]表示复件2号的信息(最多就两个)
int item_S_p[N][3];

 然后通过判断读入的q(表示这件商品的大哥是谁)分成两类;

解释一下复件这里:

现在有一个复件,价格是v,重要度是p,大哥是q

item_S_v[q][0]++;表示q有了一个复件
(item_S_p[q][0]++;表示q有了一个复件)--->实际上表示item_S_v[q][0] 和 item_S_p[q][0]表达的含义是完全相同的

接着

item_S_v[q][item_S_v[q][0]] = v;--->item_S_v[q][1]=v
item_S_p[q][item_S_p[q][0]] = v * p;--->tem_S_p[q][1]=v*p

再度入一个复件

item_S_v[q][0]++;---->2

接着

item_S_v[q][item_S_v[q][0]] = v;--->item_S_v[q][2]=v
item_S_p[q][item_S_p[q][0]] = v * p;--->tem_S_p[q][2]=v*p

这样我们就完成了对复件的描述

int n, m; cin >> n >> m;
for (int i = 1; i <= m; i++)
{
	int v, p, q;
	cin >> v >> p >> q;
	if (q == 0)
	{
		//主件
		item_M_v[i] = v;
		item_M_p[i] = p * v;
	}
	else
	{
		//副件
		item_S_v[q][0]++;
		item_S_p[q][0]++;

		item_S_v[q][item_S_v[q][0]] = v;
		item_S_p[q][item_S_p[q][0]] = v * p;
	}
}

最后

实际上这里判断复件数量的句子还可以删掉 因为没有复件就是0

转移方程也很简单

令a=我选择物品的重量

b=我选择物品的代价

dp[j]=max(dp[j],dp[j-a]+b)

for (int i = 1; i <= m; i++)
{
	for (int j = n; j >= item_M_v[i]; j--)
	{
		//只要主件
		if (j >= item_M_v[i])//---->这里还可以省略 因为第二个for循环
			dp[j] = max(dp[j], dp[j - item_M_v[i]] + item_M_p[i]);

		//如果复件数量==1
		if (item_S_p[i][0] == 1)
		{
			//要主件+复件1
			if (j >= item_M_v[i] + item_S_v[i][1])
				dp[j] = max(dp[j], dp[j - item_M_v[i] - item_S_v[i][1]] + item_M_p[i] + item_S_p[i][1]);
		}
		//如果复件数量==2
		//注意这里有三种尝试 因为哪怕你有两个复件 我也可以选择 我要那些复件
		else if (item_S_p[i][0] == 2)
		{
			//主件+1
			if (j >= item_M_v[i] + item_S_v[i][1])
				dp[j] = max(dp[j], dp[j - item_M_v[i] - item_S_v[i][1]] + item_M_p[i] + item_S_p[i][1]);
			//主件+2
			if (j >= item_M_v[i] + item_S_v[i][2])
				dp[j] = max(dp[j], dp[j - item_M_v[i] - item_S_v[i][2]] + item_M_p[i] + item_S_p[i][2]);
			//主件+1+2
			if (j >= item_M_v[i] + item_S_v[i][2] + item_S_v[i][1])
				dp[j] = max(dp[j], dp[j - item_M_v[i] - item_S_v[i][2] - item_S_v[i][1]] + item_M_p[i] + item_S_p[i][2] + item_S_p[i][1]);
		}
	}
}

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值