常见的背包问题总结与优化代码(DP)

1.01背包

优化时需要注意:第二层循环是倒序,原因这里不作说明,读者自行查找.
下面上核心代码。

	for(int i=1;i<=n;i++)///n物品数,m背包容量
		for(int j=m;j>=w[i];j--)//w[i]物品i的重量,v[i]物品i的价值
			f[j]=max(f[j],f[j-w[i]]+v[i]);

2.完全背包(每种物品次数无限的01背包)

优化时与01背包唯一不同的一点的是:第二层循环是顺序,原因这里不作说明,读者自行查找.
下面上核心代码。

for(int i=1;i<=n;i++)
	 	for(int j=w[i];j<=m;j++) 
		 	f[j]=max(f[j],f[j-w[i]]+v[i]);

3.多重背包(01背包的升级版,每个物品个数有限个)

多重背包是01背包的延伸,01背包可看作每个物品个数为1个的多重背包.
下面上核心代码。

for(int i=1;i<=n;i++)
	for(int j=1;j<=p[i];j++)
		for(int k=m;k>=w[i];k--)
			f[k]=max(f[k],f[k-w[i]]+v[i]);

4.分组背包(每组只能选一个物品的01背包变体)

优化时是三重循环,注意循环先后层顺序。
下面上核心代码。

vector<int>p[N];//二维数组p[i][j]表示第i组的第j个物品的序号数,方便查找w[i],v[i] 
int w[N],v[N],f[N],pos;//pos表示物品在那个组。 
	for(int i=1;i<=n;i++){
		cin>>w[i]>>v[i]>>pos;
		p[pos].push_back(i);
		}
	for(int i=1;i<=t;i++)
		for(int j=v;j>=0;j--)
			for(int k=0;k<p[i].size();k++)
				{
					int x=p[i][k];//第i组第k个物品的序号数 
					if(w[x]<=j) f[j]=max(f[j],f[j-w[x]]+v[x]);
				}

5.混合背包(多重背包和完全背包的合体)

就是把多重与完全背包的代码合并一下,用if判断一下就好了。
下面上核心代码。

for(int i=1;i<=n;i++)
			cin>>w[i]>>v[i]>>p[i];
		for(int i=1;i<=n;i++){
			if(!p[i]){//完全背包 
				for(int j=w[i];j<=m;j++)
					f[j]=max(f[j],f[j-w[i]]+v[i]);
			}else{ //多重背包与01背包. 
				for(int j=1;j<=p[i];j++)
					for(int k=m;k>=w[i];k--)
					f[k]=max(f[k],f[k-w[i]]+v[i]);
			}

6.双条件01背包.在(01背包优化的基础上多一维)

for(int i=1;i<=n;i++)
		for(int j=w1;j>=w1[i];j--)
			for(int k=w2;k>=w2[i];k--)
				dp[j][k]=max(dp[j][k],dp[j-w1[i]][k-w2[i]]+v[i]); 

总结:01背包,多重背包,分组背包逆序
完全背包顺序,分组背包三重循环(多的一层是遍历每组的物品,层顺序为:组数–容量–每组物品数),混合背包是多重背包和完全背包的混合体(if判断)
--------------------------------未完待续---------------------------------