限制条件:
- 一个主件有多个附件,可以选择不买和买几个
- 必须先购买主件再购买附件
所以对于一个主件最多有四种选择
这里使用位运算枚举所有选择,也可以用爆搜枚举
由于是分组背包问题,也就是同一组中选择是互斥的(主,主+附,主+2附)。
我们使用空间优化的dp数组的时候,应该先枚举体积,然后再枚举决策
for(int y=0;y<1<<servent[i].size();y++)
{
int vv=master[i].first,ww=master[i].first*master[i].second;
for(int z=0;z<servent[i].size();z++)
if(y>>z&1)
vv+=servent[i][z].first,ww+=servent[i][z].second*servent[i][z].first;
if(x>=vv)
dp[x]=max(dp[x],dp[x-vv]+ww);
}
ac代码如下
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N=60,M=32010;
typedef pair<int,int> PII;
vector<PII> master(N);
vector<PII> servent[N];
int dp[M];
int main()
{
int n,m;
cin>>m>>n;
for(int i=1;i<=n;i++)
{
int v,p,q;
cin>>v>>p>>q;
if(!q) //主件
master[i]={v,p};
else
servent[q].push_back({v,p});
}
for(int i=1;i<=n;i++)
{
if(!master[i].first&&!master[i].second) continue;
for(int x=m;x>=0;x--)
for(int y=0;y<1<<servent[i].size();y++)
{
int vv=master[i].first,ww=master[i].first*master[i].second;
for(int z=0;z<servent[i].size();z++)
if(y>>z&1)
vv+=servent[i][z].first,ww+=servent[i][z].second*servent[i][z].first;
if(x>=vv)
dp[x]=max(dp[x],dp[x-vv]+ww);
}
}
cout<<dp[m];
return 0;
}
dfs枚举版本
#include <iostream>
#include <algorithm>
using namespace std;
const int N=32010;
int dp[N];
int v[N],w[N];
vector<int> q[N];
bool st[N];
int n,m;
void dfs(int now,int fa,int vv,int ww,int j)
{
if(now==q[fa].size())
{
if(j>=vv) dp[j]=max(dp[j],dp[j-vv]+ww);
return;
}
int x=q[fa][now];
dfs(now+1,fa,vv,ww,j);
dfs(now+1,fa,vv+v[x],ww+v[x]*w[x],j);
}
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++)
{
int p;
cin>>v[i]>>w[i]>>p;
if(p==0) st[i]=true;
else
q[p].push_back(i);
}
for(int i=1;i<=n;i++)
if(st[i])
{
for(int j=m;j>=0;j--)
dfs(0,i,v[i],w[i]*v[i],j);
}
cout<<dp[m];
return 0;
}