传送门
解析:
首先我并没有读完题。。我也没有管什么只有两个依赖,,我直接写的最裸的单层依赖的背包问题。。。(其实依赖下面套分组还比这个要恶心)。
思路:
由于我们直接枚举所有策略,对于一个物品集合是O(2∣S∣)O(2^{|S|})O(2∣S∣)的,所以我们可以先在集合内部做一次010101背包,注意,为了减小最终的物品个数,可以使用恰好背包。
然后就是集合与集合之间的分组背包裸题了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
cs int N=65,M=32004;
vector<pair<int,int> > vec[N];
vector<pair<int,int> > item[N];
int v[N],p[N],q[N];
int f[M];
int n,m;
signed main(){
scanf("%d%d",&n,&m);
for(int re i=1;i<=m;++i){
scanf("%d%d%d",&v[i],&p[i],&q[i]);
if(q[i]){
vec[q[i]].push_back(make_pair(v[i],p[i]));
}
}
for(int re i=1;i<=m;++i){
if(!vec[i].empty()){
memset(f,-1,sizeof f);
f[0]=0;
for(int re j=0;j<vec[i].size();++j){
for(int re k=n-v[i];k>=vec[i][j].first;--k){
if((~f[k-vec[i][j].first])&&f[k]<f[k-vec[i][j].first]+vec[i][j].first*vec[i][j].second){
f[k]=f[k-vec[i][j].first]+vec[i][j].first*vec[i][j].second;
}
}
}
for(int re k=n-v[i];k;--k){
if(~f[k]){
item[i].push_back(make_pair(k+v[i],f[k]+v[i]*p[i]));
}
}
}
if(!q[i]){
item[i].push_back(make_pair(v[i],v[i]*p[i]));
}
}
memset(f,0,sizeof f);
for(int re i=1;i<=m;++i)
for(int re k=n;k;--k)
for(int re j=0;j<item[i].size();++j)
if(k>=item[i][j].first)f[k]=max(f[k],f[k-item[i][j].first]+item[i][j].second);
cout<<f[n];
return 0;
}