混合背包问题、二维费用的背包问题、分组背包问题、有依赖的背包问题

闫神视频笔记

视频链接

混合背包问题就是结合01背包、完全背包、多重背包的问题

混合背包问题(题目链接
解题思路:

可以先将多重背包部分用二进制优化的方法转化成01背包问题,最后就剩下01背包和完全背包,而两者计算的差别就是循环的顺序,一个向前,一个向后,所以只要在循环的时候判断一下就行了。

代码:
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<cstdio>
#include<cmath>
using namespace std;
const int N = 1010;
int n,m,v,w,s,f[N];
struct Good{
	int type,v,w;
}; 
vector<Good>goods;
int main(){
//	freopen("1.txt","r",stdin);
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>v>>w>>s;
		if(s<0) goods.push_back({-1,v,w});
		else if(s==0) goods.push_back({0,v,w});
		else{
			for(int j=1;j<=s;j*=2){
				s-=j;
				goods.push_back({-1,v*j,w*j});
			}
			if(s>0) goods.push_back({-1,v*s,w*s}); 
		}
	}
	for(auto good:goods){
		if(good.type==-1){
			for(int i=m;i>=good.v;i--) f[i] = max(f[i],f[i-good.v]+good.w);
		}else{
			for(int i=good.v;i<=m;i++) f[i] = max(f[i],f[i-good.v]+good.w);
		}
	}
	cout<<f[m]<<endl;
	return 0;
}
二维费用的背包问题(题目链接
解题思路:

二维费用的背包问题就是01背包的升级版,背包和物品除了有体积还有重量。解题思路就是将原来的一维数组升级为二维数组就行了。这样f[i][j]代表的就是体积为i,重量为j的最优解,计算过程中多一层循环就行了。

代码:
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<cstdio>
#include<cmath>
using namespace std;
const int N = 1010;
int n,V,M,v,m,w,f[N][N]; 
int main(){
//	freopen("1.txt","r",stdin);
	cin>>n>>V>>M;
	for(int i=0;i<n;i++){
		cin>>v>>m>>w;
		for(int j=V;j>=v;j--){
			for(int k=M;k>=m;k--){
				f[j][k] = max(f[j][k],f[j-v][k-m]+w);
			}
		}
	}
	cout<<f[V][M]<<endl;
	return 0;
}
分组背包问题(题目链接
解题思路:

分组背包问题就是每个物品有组别,每个组最多只能选择一个物品。也就是01背包的变种。思路就是将一个组里所有的物品都遍历一遍就行了(即原来是只有不选两种选择,现在是有s+1种选择,都不选选第1个物品选第2个物品…)

代码1(我的):
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<cstdio>
#include<cmath>
using namespace std;
const int N = 110;
int n,m,k,v,w,f[N],g[N];
int main(){
//	freopen("1.txt","r",stdin);
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>k;
		memcpy(g,f,sizeof f);
		for(int ii=0;ii<k;ii++){
			cin>>v>>w;
			for(int j=m;j>=v;j--){
				f[j] = max(f[j],g[j-v]+w);
			}
		} 
	}
	cout<<f[m]<<endl;
	return 0;
}
代码2(大佬的):
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<cstdio>
#include<cmath>
using namespace std;
const int N = 110;
int n,m,s,v[N],w[N],f[N];
int main(){
//	freopen("1.txt","r",stdin);
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>s;
		for(int j=0;j<s;j++){
			cin>>v[j]>>w[j];
		} 
		for(int j=m;j>=0;j--){
			for(int k=0;k<s;k++){
				if(j-v[k]>=0) f[j] = max(f[j],f[j-v[k]]+w[k]);
			}
		}
	}
	cout<<f[m]<<endl;
	return 0;
}
有依赖的背包问题(题目链接
解题思路:

我们用二维数组 f[i][j] 来表示以结点 i 为根的子树,在体积不超过 j 的情况下,可以得到的最大价值。
对于该子树,我们遍历根结点的所有孩子,其中dfs(children[root][i]);可以理解为用递归求出这个孩子在各种情况下的最优解。之后再用该孩子的数据来更新根结点的最优解。
我们需要先遍历该子树分配到的体积的各种情况,再遍历该孩子分配到的体积的各种情况,更新最优解。
(目前的水平只能这么潦草地解释)

代码:
#include<iostream>
#include<cmath>
#include<cstring>
#include<vector>
#define N 110
#define INF 0x7fffffff
using namespace std;
vector<int>children[N];
int n,m,v[N],w[N],p[N],f[N][N];
void dfs(int root){
	for(int i=v[root];i<=m;i++){
		f[root][i]=w[root];
	}
	for(int i=0;i<children[root].size();i++){
		dfs(children[root][i]);
		for(int j=m;j>=v[root];j--){
			for(int k=0;k<=j-v[root];k++){
				f[root][j] = max(f[root][j],f[root][j-k]+f[children[root][i]][k]);
			}
		}
	}
}
int main(){
//	freopen("1.txt","r",stdin);
	int root;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>v[i]>>w[i]>>p[i];
		if(p[i]==-1) root=i;
		else children[p[i]].push_back(i);
	}
	dfs(root);
	cout<<f[root][m]<<endl;
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值