#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node{
int v;
int w;
int tag;//表明是否是主件 ,或者是该附件的主件编号
}thing[60],pat[60][60];//thing数组用来存储输入的物品信息,pat数组用来存储第i个物品的第j个附件信息,信息(结构体)的意思
void print(node a){
cout<<a.v<<" "<<a.w<<" "<<a.tag<<endl;
}
int t[60]; //记录第i个主件的附件数量,全局变量初始化为0
int cnt[60]; //记录第i个主件在附件经过0,1背包问题处理后,计算出的附件含有的情况个数
int f[33000];
int value[60][60];//记录一个主件分组的情况
int get[60][60];//记录第i个物品的第j种情况的所获得的比重
int num;
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>thing[i].v>>thing[i].w>>thing[i].tag;
if(thing[i].tag>0){
num=++t[thing[i].tag];
pat[thing[i].tag][num].v=thing[i].v;
pat[thing[i].tag][num].w=thing[i].w;
pat[thing[i].tag][num].tag=thing[i].tag;
}
}
for(int i=1;i<=m;i++){
if(t[i]){ //如果当前物品有附件
memset(f,-1,sizeof(f));//恰好背包的处理,-1表示不恰好取到此价值
f[0]=0;
for(int j=1;j<=t[i];j++){ //0,1背包问题
for(int k=n-thing[i].v;k>=pat[i][j].v;k--){
if(f[k]<f[k-pat[i][j].v]+pat[i][j].v*pat[i][j].w&&f[k-pat[i][j].v]!=-1) //需要存在这种恰好的情况
f[k]=f[k-pat[i][j].v]+pat[i][j].v*pat[i][j].w;
}
}
//存储每种价值与比重的情况
for(int j=0;j<=n-thing[i].v;j++){
if(f[j]!=-1){
cnt[i]++;//记录一个分组有多少种花费和取得的最大比重与价值的乘积
value[i][cnt[i]]=thing[i].v+j; //第i个物品(分组)的第cnt[i]种情况的花费
get[i][cnt[i]]=thing[i].w*thing[i].v+f[j];
}
}
}
if(!thing[i].tag){ //只买主件 ,千万不要写成t[i]==0,我们要计算的是主件与附件的所有情况;所以一个主件有附件的情况下,在上面的式子处理一遍后,会计算出主件与附件搭配出的情况,而在个式子如果是主件,则cnt会继续增加;
cnt[i]++;
value[i][cnt[i]]=thing[i].v;
get[i][cnt[i]]=thing[i].w*thing[i].v;
}
}
//下面进行分组背包的处理
memset(f,0,sizeof(f));
for(int i=1;i<=m;i++){
for(int j=n;j>=0;j--){
for(int k=1;k<=cnt[i];k++){
if(j>=value[i][k])
f[j]=max(f[j],f[j-value[i][k]]+get[i][k]);
}
}
}
cout<<f[n]<<endl;
return 0;
}
洛谷P1064金明的预算方案
最新推荐文章于 2024-07-28 12:57:16 发布