背包问题(入门基础版)

目录

一、【NOIP2001】装箱问题

1.)二维基础版:

2.)01滚动

3.)“就地滚动” ​编辑

01背包

 完全背包

 多重背包

二维费用背包问题

 分组背包


一、【NOIP2001】装箱问题

传送门-(牛客)

背包问题(入门基础版)_第1张图片

 背包问题(入门基础版)_第2张图片

 背包问题(入门基础版)_第3张图片

 【动画演示真的yyds好嘛^^】

重中之重  状态转移方程 f[i][j] = f[i-1][j] || f[i-1][ j-v[i] ] 其实就是逆着想;

对第 i 个物品就两种选择:要 或 不要;

在 f[i-1][ j-v[i] ] 状态时 有,可以在此基础上放入目前的i 号物品,得到  f[i][j] 有;->此为“要”的选择;另一种情况,在上一次,即  f[i-1][j] 时已经有(意为有 j 体积了),这一轮第 i 个物品不要,所以体积还是原来的 j , 即 f[i][j] ;

其中有 “继承” 上一轮状态 并新添本次选择了的物品后的状态  的感觉。

理解了后  用最易懂的二维数组版写:

1.)二维基础版:

#include
using namespace std;
int v,n,a[40],f[40][20010];
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>v>>n;
	f[0][0]=1;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++){
		for(int j=0;j<=v;j++){
			if(j>=a[i])f[i][j]=(f[i-1][j]||f[i-1][j-a[i]]);
			else f[i][j]=f[i-1][j];
		}
	}
	for(int i=v;i>=0;i--){
		if(f[n][i]){
			cout<

2.)01滚动

背包问题(入门基础版)_第4张图片

更新第0行后,更新第1行,再要更新第2行的时候,发现只与它的前一行也就是第1行有关,第0行已经没用了,这时将第2行装到第0行里,后面再要写第3行时,写到第1行里……依此类推,也就是i , i-1变成了i%2, (i-1)%2等等

//01滚动 
#include
using namespace std;
int v,n,a[40],f[2][20010];
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>v>>n;
	f[0][0]=1;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++){
		for(int j=0;j<=v;j++){
			if(j>=a[i])f[i%2][j]=(f[(i-1)%2][j]||f[(i-1)%2][j-a[i]]);
			else f[i%2][j]=f[(i-1)%2][j];
		}
	}
	for(int i=v;i>=0;i--){
		if(f[n%2][i]){    // 注意最后判断的数组是n%2不一定是1 
			cout<

3.)“就地滚动” 背包问题(入门基础版)_第5张图片

 背包问题(入门基础版)_第6张图片

//就地滚动  倒序更新 
#include
using namespace std;
int v,n,a[40],f[20010];
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>v>>n;
	f[0]=1;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++){
		for(int j=v;j>=a[i];j--){
			f[j]=f[j]||f[j-a[i]];  //不要落写"f[j]||" 
		}
	}
	for(int i=v;i>=0;i--){
		if(f[i]){
			cout<

01背包

背包问题(入门基础版)_第7张图片

 完全背包

背包问题(入门基础版)_第8张图片

 多重背包

背包问题(入门基础版)_第9张图片

 背包问题(入门基础版)_第10张图片

 背包问题(入门基础版)_第11张图片

二维费用背包问题

背包问题(入门基础版)_第12张图片

 背包问题(入门基础版)_第13张图片

 背包问题(入门基础版)_第14张图片

 分组背包

背包问题(入门基础版)_第15张图片

 背包问题(入门基础版)_第16张图片

 【特别注意 “所有的 i 属于组k ”的循环要在V的循环里面,因为要保证这一组的每个物品都是只选它时的情况,如果k循环放到了外面,那就会变成同一组中的物品a在基于同组物品b已选的情况下转移得到,而事实上它们会起冲突……】

你可能感兴趣的:(动态规划,动态规划,c++,算法)