金明的预算方案

Description

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的。

如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

Analysis

第一次遇到的依赖性背包问题。

如果取消附件的限制,那么这题可以用01背包解决。加上附件之后,相当于1个主件变成了4件物品(附件的选择导致),且此4件物品互相冲突。因为4常数非常小..所以在计算到此主件组时,只要枚举4种情况,找出最优情况就行了。

但是如果附件变多了,组合数太多,为2^n,该怎么办呢?不难发现主件组中各种组合进行了多次冗余计算,可以想到先给主件组中的组合来一发01背包,求出各种价格下的最大获得值,这样就把所有的组合化成了价格数个物品。当然这题无需优化。

Code

#include <bits/stdc++.h>

int n,m,dp[32001],id[101];
std::vector <int> gift[101];

struct node{
	int v,w;
}th[101];

int main(){
	freopen("budget.in","r",stdin);
	freopen("budget.ans","w",stdout);
	std::cin>>n>>m;
	for(int i=1;i<=m;i++){
		int q;
		std::cin>>th[i].v>>th[i].w>>q;
		th[i].w*=th[i].v;
		if(!q)id[++id[0]]=i;
		else gift[q].push_back(i);
	}
	m=id[0];
	for(int i=1;i<=m;i++)
		for(int j=n;j>=th[id[i]].v;j--){
			int v=th[id[i]].v;
			int w=th[id[i]].w;
			dp[j]=std::max(dp[j],dp[j-v]+w);
			if(gift[id[i]].empty())continue;
			for(int k=0;k<gift[id[i]].size();k++){
				int s=gift[id[i]][k];
				if(j>=th[s].v+v)
					dp[j]=std::max(dp[j],dp[j-v-th[s].v]+w+th[s].w);
			}
			if(gift[id[i]].size()>1){
				int s0=gift[id[i]][0];
				int s1=gift[id[i]][1];
				if(j>=th[s0].v+th[s1].v+v)
					dp[j]=std::max(dp[j],dp[j-v-th[s0].v-th[s1].v]+w+th[s0].w+th[s1].w);
			}
		}
	std::cout<<dp[n]<<std::endl;
	return 0;
}
posted @ 2018-08-17 11:41  Srzer  阅读(169)  评论(0编辑  收藏  举报