洛谷P1064金明的预算方案

1 篇文章 0 订阅


题目链接

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值