【题解】洛谷P1064[NOIP2006]金明的预算方案 有依赖的背包问题

该博客详细介绍了如何解决有依赖的背包问题,具体到洛谷P1064[NOIP2006]金明的预算方案。博主通过分析决策的五种情况,给出了状态转移方程,并强调了这类问题的处理技巧。

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

题目链接
在这里插入图片描述
在这里插入图片描述


我们把附件和它的主件归到一组,其中主件为每组第一项编号为0。因为每组最多两个附件,对于每一组,决策有以下五种(假定存在两个附件):
1.不取这组
2.只取主件
3.取主件和附件1
4.取主件和附件2
5.取主件和附件1附件2
F [ i , j ] F[i,j] F[i,j] 表示考虑到第 i i i 组容量为 j j j 时的最大价值
状态转移方程(假定存在两个附件)
F [ i , j ] = max ⁡ { F [ i − 1 , j ] F [ i − 1 , j − v [ i ] [ 0 ] ] + v [ i ] [ 0 ] × p [ i ] [ 0 ] F [ i − 1 , j − v [ i ] [ 0 ] − v [ i ] [ 1 ] ] + v [ i ] [ 0 ] × p [ i ] [ 0 ] + v [ i ] [ 1 ] × p [ i ] [ 1 ] F [ i − 1 , j − v [ i ] [ 0 ] − v [ i ] [ 2 ] ] + v [ i ] [ 0 ] × p [ i ] [ 0 ] + v [ i ] [ 2 ] × p [ i ] [ 2 ] F [ i − 1 , j − v [ i ] [ 0 ] − v [ i ] [ 1 ] − v [ i ] [ 2 ] ] + v [ i ] [ 0 ] × p [ i ] [ 0 ] + v [ i ] [ 1 ] × p [ i ] [ 1 ] + v [ i ] [ 2 ] × p [ i ] [ 2 ] F[i,j]=\max\begin{cases}F[i-1,j]\\F[i-1,j-v[i][0]]+v[i][0]\times p[i][0]\\F[i-1,j-v[i][0]-v[i][1]]+v[i][0]\times p[i][0]+v[i][1]\times p[i][1]\\F[i-1,j-v[i][0]-v[i][2]]+v[i][0]\times p[i][0]+v[i][2]\times p[i][2]\\F[i-1,j-v[i][0]-v[i][1]-v[i][2]]+v[i][0]\times p[i][0]+v[i][1]\times p[i][1]+v[i][2]\times p[i][2]\end{cases} F[i,j]=maxF[i1,j]F[i1,jv[i][0]]+v[i][0]×p[i][0]F[i1,jv[i][0]v[i][1]]+v[i][0]×p[i][0]+v[i][1]×p[i][1]F[i1,jv[i][0]v[i][2]]+v[i][0]×p[i][0]+v[i][2]×p[i][2]F[i1,jv[i][0]v[i][1]v[i][2]]+v[i][0]×p[i][0]+v[i][1]×p[i][1]+v[i][2]×p[i][2]

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int n,m,v[61],p[61],w[61],tot,q[61],gro[61],f[32001];
vector<int>g[61];
int main()
{
	//freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    	scanf("%d%d%d",&v[i],&p[i],&q[i]),w[i]=v[i]*p[i];
    for(int i=1;i<=m;i++)
        if(q[i]==0)g[++tot].push_back(i),gro[i]=tot;
    for(int i=1;i<=m;i++)
        if(q[i]>0)g[gro[q[i]]].push_back(i);
    for(int i=1;i<=tot;i++)
    	for(int j=n;j>=0;j--)
    	{
    		if(j>=v[g[i][0]])f[j]=max(f[j],f[j-v[g[i][0]]]+w[g[i][0]]);
    		if(g[i].size()>=2&&j>=v[g[i][0]]+v[g[i][1]])f[j]=max(f[j],f[j-v[g[i][0]]-v[g[i][1]]]+w[g[i][0]]+w[g[i][1]]);
    		if(g[i].size()>=3)
    		{
    			if(j>=v[g[i][0]]+v[g[i][1]]+v[g[i][2]])f[j]=max(f[j],f[j-v[g[i][0]]-v[g[i][1]]-v[g[i][2]]]+w[g[i][0]]+w[g[i][1]]+w[g[i][2]]);
    			if(j>=v[g[i][0]]+v[g[i][2]])f[j]=max(f[j],f[j-v[g[i][0]]-v[g[i][2]]]+w[g[i][0]]+w[g[i][2]]);
			}
		}
	printf("%d\n",f[n]);
    return 0;
}

总结

一道典型的有依赖的背包问题,要学会如何处理这类问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值