0.提示:学习多重背包之前最好先学习01背包!!
1.完全背包的定义
完全背包是研究这样一种问题:有n个物体,每个物体的大小为w,价值为v,每个物体都有 无数个,要把他们装进一个大小为t的背包,使价值最大化。
(注意:01背包的物体数只有一个,不要把他们搞混了)
2.贪心是否可以得到最优解?
不可以,例如:
参见我的另一篇文章:(卡价值贪心)https://blog.youkuaiyun.com/luogu_hezhenmin1/article/details/142673321?spm=1001.2014.3001.5501m
又比如:
有3个物体,背包大小为10
w1=6,v1=1;
w2=4,v2=8;
w3=10,v3=10;
贪心会选第一个第二个,但选第3个价值更大(卡性价比贪心)
结论:贪心不可以求得最优解
3.如何求解?
3.1如果选择第j个物体,且i>=j,那么
dp[i]=dp[i-w[j]]+v[j];//如果选择第j个物体
3.2如果不选择第j个物体,那么
dp[i]=dp[i];//不选
3.3那么最大价值就是
dp[i]=max(dp[i],dp[i-w[i]]+v[i]);
看到这里,有人就会发问了:这不是跟01背包一样吗?
说的没错,完全背包的状态转移方程跟01背包一样,但是在01背包的学习中,为了防止一个物体多次选择,所以我们的第二重循环是倒序枚举,为的就是防止dp[j-w[i]]在dp[j]之前就已经状态转移了,现在我们的第二重循环是正序枚举,所以只要j-w[i]>=w[i],那么dp[j]就有可能会等于dp[j-2*w[i]]+2*v[i],以此类推。
4.完全背包的例题与代码
抽象为:有n(n<=1e4)个物体,每个物体的大小为w(w<=1e4),价值为v(v<=1e4),每个物体都有 无数个,要把他们装进一个大小为t(t<=1e7)的背包,使价值最大化。
代码:
#include<bits/stdc++.h>
using namespace std;
int t,m;
long long dp[10000002];
int v[1000002],w[1000002];
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>t>>m;
for(int i=1;i<=m;i++)
cin>>v[i]>>w[i];
for(int i=1;i<=m;i++)
for(int j=v[i];j<=t;j++)
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
cout<<dp[t];
return 0;
}
注意:十年OI一场空,不开long long 见祖宗!!!
例题:hdu
5.几句闲话
背包计数问题的状态转移方程是dp[i]+=dp[i-w[i]];
谢谢