题目链接:http://noip.ybtoj.com.cn/contest/50/problem/5
分析
分开主件和附件,因为最多有两个附件,所以只有5种情况:
- 啥都不买
- 只买主件
- 主件+附件1
- 主件+附件2
- 主件+附件1+附件2
找几个数组分别存主件,附件1,附件2。
转移:
枚举每件物品,枚举背包容量。方程:
f [ j ] = m a x ( f [ j ] , f [ j − v [ i ] ] + v [ i ] ∗ q [ i ] ) ; f[j]=max(f[j],f[j-v[i]]+v[i]*q[i]); f[j]=max(f[j],f[j−v[i]]+v[i]∗q[i]);
买附件同理,就多减掉容量,乘上重要度。
因为不一定花最多钱重要度一定最大,所以对 f f f数组取min
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int f[50001],v[70],q[70],v1[70],q1[70],v2[70],q2[70];
int main()
{
int n,m;
cin>>n>>m;
/*q,v:如是主件则存在这里
q1,v1:如是附件一存在这里
q2,v2:如是附件二则存在这里*/
f[0]=0;
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if (c==0)
{
v[i]=a;q[i]=b; //存为主件
}
else
{
if(q1[c]==0)
{
q1[c]=b;v1[c]=a;
}
else
{
q2[c]=b;v2[c]=a;
}
//存为附件一或附件二
}
}
for(int i=1;i<=m;i++)
{
for(int j=n;j>=v[i];j--)
{
if(j-v[i]>=0) f[j]=max(f[j],f[j-v[i]]+v[i]*q[i]);//只买一个主件
if(j-v[i]-v1[i]>=0) f[j]=max(f[j],f[j-v[i]-v1[i]]+v[i]*q[i]+v1[i]*q1[i]);//买主件和附件一
if(j-v[i]-v2[i]>=0) f[j]=max(f[j],f[j-v[i]-v2[i]]+v[i]*q[i]+v2[i]*q2[i]);//买主件和附件二
if(j-v[i]-v1[i]-v2[i]>=0) f[j]=max(f[j],f[j-v[i]-v1[i]-v2[i]]+v[i]*q[i]+v1[i]*q1[i]+v2[i]*q2[i]);//买主件和两个附件
}
}
int ans=0;
for(int j=1;j<=n;j++)
{
if(f[j]>ans) ans=f[j];
}
cout<<ans;
return 0;
}