刷题记录:牛客NC16671[NOIP2006]金明的预算方案

传送门:牛客

题目描述:

题目较长,此处省略
输入:
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
输出:
2200

这道题应该可以说是这道题的升级版,也算一道 01 背包的题目 01背包的题目 01背包的题目,但是是背包的变种,暂且称之为有依赖的背包吧

主要思路:

  1. 虽然这道题刚开始看题觉得一头雾水,但是当我们仔细分析一下之后这道题还是可做的.我们只要在我们的01背包的思想上面改一下即可.我们当时做01背包时是怎么做的,是不是对于一个物品有两种决策状态(要么我们选取这个物品,要么不选),那么现在我们只不过多了三种决策而已,分别是对于一个附属品,我们只能在有主件的情况下才只能选择,因此我们只要枚举我们的主件即可,对于我们的附件.在枚举我们的主件时,假设我们的体积足够,然后随着主件一起减去体积,一起加上价值,因此有选取主件+附件1,主件+附件2,主件+附件1+附件2这三种决策,我们只要在我们的01背包的模板中添加即可(但是注意我们只需枚举主件)

注意:我们此题需要使用long long

下面是具体的代码部分:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int n,m;
struct Thing{
	ll w,v,flag;
}zhujian[maxn],fujian[maxn][3];
ll num[maxn];ll dp[maxn];
int main() {
	n=read();m=read();
	ll v,p,q;
	for(int i=1;i<=m;i++) {
		v=read();p=read();q=read();
		if(q==0) {
			zhujian[i].w=p*v;
			zhujian[i].v=v;
			zhujian[i].flag=1;
		}else {
			num[q]++;
			fujian[q][num[q]].w=p*v;
			fujian[q][num[q]].v=v;
		}
	}
	for(int i=1;i<=m;i++) {
		if(zhujian[i].flag==0) continue;
		for(int j=n;j>=zhujian[i].v;j--) {
			dp[j]=max(dp[j],dp[j-zhujian[i].v]+zhujian[i].w);
			if(j>=zhujian[i].v+fujian[i][1].v){
				dp[j]=max(dp[j],dp[j-zhujian[i].v-fujian[i][1].v]+zhujian[i].w+fujian[i][1].w);
			}
			if(j>=zhujian[i].v+fujian[i][2].v){
				dp[j]=max(dp[j],dp[j-zhujian[i].v-fujian[i][2].v]+zhujian[i].w+fujian[i][2].w);
			}
			if(j>=zhujian[i].v+fujian[i][1].v+fujian[i][2].v) {
				dp[j]=max(dp[j],dp[j-zhujian[i].v-fujian[i][1].v-fujian[i][2].v]+fujian[i][1].w+fujian[i][2].w+zhujian[i].w);
			}
		}
	}
	cout<<dp[n]<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值