背包

97 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

一、01背包(每个物品放一次)

一维

有N个物品  背包总容量为V   每个物品有w(重量)v(价值)  每个物品放一次   在不超过V的前提下求背包所装最大价值

题目:www.luogu.org/problemnew/…

for(int i=1;i<=N;i++){
	for(int j=V;j>=w[i];j--)
	  f[j]=max(f[j],f[j-w[i]]+v[i]);
} 

二维

有N个物品  背包总容量为V,价值总和T   每个物品有v(重量)v(价值) t(价钱)  每个物品放一次   在不超过V且不超过T的前提下求背包所装物品最多价钱

题目:www.luogu.org/problemnew/…

for(int i=1;i<=N;i++){
		for(int j=V;j>=v[i];j--){
			for(int k=T;k>=t[i];k--)
			  f[j][k]=max(f[j][k],f[j-v[i]][k-t[i]]+r[i]);
		}
	}

二、完全背包(物品可以放无限次)

有N个物品  背包总容量为V   每个物品有w(重量)v(价值)  每个物品放无限次   在不超过V的前提下求背包所装最大价值

for(int i=1;i<=N;i++){
	for(int j=w[i];j<=V;j++)
	  f[j]=max(f[j],f[j-w[i]]+v[i]);
} 

 

三、多重背包

有N个物品  背包总容量为V   每个物品最多有s件,w(重量)v(价值)     在不超过V的前提下求背包所装最大价值

for(int i=1;i<=N;i++){
	for(int j=V;j<=w[i];j--){
		for(int k=1;k<=s[i]&&k*w[i]<=j;k++)
		 f[j]=max(f[j],f[j-k*w[i]]+k*v[i])
	}
}

当s>20000   N>1000 时  二次进制存储优化  拆分s  然后再01背包

#include<iostream>
#include<cstring>
#include<algorithm> 
#include<vector>
using namespace std;
struct Good{//定义结构体 
	int w,v;
};
const int S=2010;
int f[S];
int main(){
	int N,V;
	cin>>N>>V;
	vector<Good> goods;//不确定大小  用容器 
	for(int i=1;i<=N;i++){
		int s,w,v;
		cin>>s>>w>>v;
		for(int k=1;k<=s;k*=2){
		   s=k;
		   goods.push_back({w*s,v*s});
		} 
		if(s>0) goods.push_back({w*s,v*s});//不是2的整n次方倍 
	} 
	N=goods.size();
	for(int i=1;i<=N;i++)
	   for(int j=V;j>=goods[i].w;j--)
	     f[j]=max(f[j],f[j-goods[i].w]+goods[i].v);
    cout<<f[V]<<endl;
    return 0;
} 

单调队列优化

 

四、组合背包

一共有N组数据  背包容量V   对于每组数据有重量m,价值v,  s   有三种数据   s==-1  每个物品只能用依次                                                                                                                                                                              s==0  每个物品可用无限次                                                                                                                                                                                s  每个物品有s个

二进制容器存储  ,遍历0~N是判断用01背包还是完全背包

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace  std;
struct Good{
	int pd;
	int m,v;//每个物品所占体积和价值 
}; 
const int SS=1005;
int f[SS];
int N,V;//数量   体积
vector<Good> goods;
int main(){
	cin>>N>>V;
	for(int i=0;i<N;i++){
		int m,v,s;
		cin>>m>>v>>s;
		if(s==-1) goods.push_back({-1,m,v});
		else if(s==0) goods.push_back({0,m,v});
		else{
			for(int k=1;i<=s;i*=2){
				s-=k;
				goods.push_back({-1,m*k,v*k});
			} 
			if(s>0) goods.push_back({-1,m*s,v*s});
		}
	}
	N=goods.size();
	for(int i=0;i<N;i++){
		if(goods[i].pd==0)
		 {
		 	for(int j=goods[i].m;j<=V;j++)
		 	  f[j]=max(f[j],f[j-goods[i].m]+goods[i].v);//01背包 
		 }
		else{
			for(int j=V;j>=goods[i].m;j--)
			  f[j]=max(f[j],f[j-goods[i].m]+goods[i].v);//完全背包 
		}
	}
	cout<<f[V]<<endl;
	return 0; 
}

五、分组背包

有n个物品,物品分类有m种   每种物品只能选一个 每件物品体积为w 价值为v   求在不超过背包体积V 的前提先  背包的最大价值。

for(int i=0;i<m;i++){
	for(int j=V;j>0;j--){
		for(int k=0;k<x[i];k++)//x 是每类物品的个数 
		  if(j>w[i][k])
		 f[j]=max(f[j],f[j-w[i][k]]+v[i][k]);//w[i][k] 第i类物品第k个的体积  w[i][k] 第i类物品第k个的价值 
	}
}

题目:www.luogu.org/problemnew/…

#include<iostream>
using namespace std;
int m,n;
int a[1005],b[1005],c[105][20],f[1005],cc[101],cn=0;
int main(){
	cin>>m>>n;
	for(int i=1;i<=n;i++){
		int C;
	    cin>>a[i]>>b[i]>>C;	
	    cn=max(cn,C);
	    cc[C]++;
	    c[C][cc[C]]=i;
	}
	for(int i=1;i<=cn;i++){
		for(int j=m;j>=0;j--){
			for(int k=1;k<=cc[i];k++){
				if(j>=a[c[i][k]])
				f[j]=max(f[j],f[j-a[c[i][k]]]+b[c[i][k]]);
			 }
		}
	}
	cout<<f[m]<<endl;
	return 0;
}