背包的几个问题

1271:【例9.15】潜水员

二位费用的背包

背包容量 氧气氮气的体积

背包费用 罐子的重量

求费用最小值

倒着for两维体积,原因是如果正着for,可能一件物品多次放到背包里

1295:装箱问题

状压如下,分析复杂度:n<=30,O((1<<30 ) * 30)=O(2e9 *30)= 6e10

肯定会T的!

for(int i=0;i<=(1<<n);i++){//2e9
		int ans0=0;int t=i;
		int num=n;while(t && num){//30
			if(t&1)	ans0+=ti[num];
			t/=2;
			num--;
		}
		if(ans0 <= v && ans0>ans)	ans=ans0;
	}
	ans=v-ans;
	cout << ans <<endl;

二位数组如下

cin>>v>>n;
	for(int i=1;i<=n;i++)	cin>>ti[i];
	for(int i=1;i<=n;i++){
		for(int j=v;j>=ti[i];j--){
			if(f[i-1][j-ti[i]]+ti[i] <= v)
			f[i][j]=max(f[i][j],f[i-1][j-ti[i]]+ti[i]);
		}
	}
	for(int i=1;i<=n;i++)	ans=max(ans,f[i][v]);
	ans=v-ans;
	cout<<ans<<endl;

然鹅错了

滚动数组如下

cin>>v>>n;
for(int i=1;i<=n;i++)	cin>>ti[i];
for(int i=1;i<=n;i++){
	for(int j=v;j>=ti[i];j--){
		//if(f[j-ti[i]]+ti[i] <= v)
		f[j]=max(f[j],f[j-ti[i]]+ti[i]);

		if(f[j] > ans && f[j] < v)	ans=f[j];
	}
}
//ans=f[v];
ans=v-ans;
cout<<ans<<endl;

是错的,错误答案和二位数组一样

另一个如下

cin>>v>>n;
for(int i=1;i<=n;i++)	cin>>ti[i];
for(int i=1;i<=n;i++){
	for(int j=v;j>=ti[i];j--){
		if(f[j-ti[i]]+ti[i] <= v)
		f[j]=max(f[j],f[j-ti[i]]+ti[i]);
		//if(f[j] > ans && f[j] < v)	ans=f[j];
	}
}
ans=f[v];
ans=v-ans;
cout<<ans<<endl;

这便对了。是1维的,不记录无用状态的一维的。

对于1、2维,我是这么想的:如果是2维,意味着第i个物品只能使用前i个物品的状态,

如果是1维,第i 个物品还能使用同样是第i 个物品,但是体积更小的状态。但是这样可能会出现第i个物品选两次的情况不是吗?但是如果倒着枚举就不会了(hh我就是倒着枚举的)

哦,好像应该这么解释:如果是一维的,那么第i 个物品相当于使用的是前1~i-1的所有物品的状态,所以会更优。

但是根据这个,我们可以给二维的程序加一句:

f[i][j]=max(f[i][j],f[i-1][j]);

便可达到同一维数组一样的效果。

然鹅还不对

经过调试,我发现了 问题所在:

1.j应该枚举到0,而不是枚举到ti[i] ,这样才能正确的顺延

2.其实if(f[j-ti[i]]+ti[i] <= v) 这一句是没用的,因为j的范围和f [i] [j]的范围是一样的,既然j<v,f [i] [j] 也就不会大于v了

最终的二维代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <queue>

using namespace std;


int v,n,ti[33];
int ans;
int f[33][20010];
int main()
{
	
	cin>>v>>n;
	for(int i=1;i<=n;i++)	cin>>ti[i];
	for(int i=1;i<=n;i++){
		for(int j=v;j>=0;j--){
			f[i][j]=max(f[i][j],f[i-1][j]);
			if(j >= ti[i])
				f[i][j]=max(f[i][j],f[i-1][j-ti[i]]+ti[i]);
		}
	}
	ans=f[n][v];
	ans=v-ans;
	cout<<ans<<endl;
	
	
	return 0;
}
/*
10 3
1
5
7
*/

原文地址:https://www.cnblogs.com/ZhengkunJia/p/12932349.html