2018.11.09【NOIP2006】【洛谷P1064】金明的预算方案(有依赖的背包问题)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/83892433

传送门


解析:

首先我并没有读完题。。我也没有管什么只有两个依赖,,我直接写的最裸的单层依赖的背包问题。。。(其实依赖下面套分组还比这个要恶心)。

思路:

由于我们直接枚举所有策略,对于一个物品集合是 O ( 2 S ) O(2^{|S|}) 的,所以我们可以先在集合内部做一次 01 01 背包,注意,为了减小最终的物品个数,可以使用恰好背包。

然后就是集合与集合之间的分组背包裸题了。


代码:

#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;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/83892433