多重背包和完全背包的基础都是01背包
多重背包
有
N
种物品和⼀个容量为
V
的背包。第
i
种物品最多有a
i
件可⽤,每件耗费的空间是v
i
,价
值是w
i
。求解将哪些物品装⼊背包可使这些物品的耗费的空间 总和不超过背包容量,且价
值总和最⼤。
我们将每一件物品看成独立的就可以套用01背包了
代码实现
#include<bits/stdc++.h>
using namespace std;
int v[10000],w[10000];
int dp[10000];
int main()
{
int n,c;
scanf("%d%d",&n,&c);
int cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a,&V,&W);
for(int j=1;j<=a;j++)
{
v[++cnt]=V;
w[cnt]=W;
}
}
for(int i=1;i<=cnt;i++)//填表
{
for(int j=c;j>=0;j--)//j必须从后面开始,这样dp[j]的改变才不会影响前面的dp
{
if(j>=w[i]&&dp[j-w[i]]+v[i]>dp[j])
{
dp[j]=dp[j-w[i]]+v[i];
}
}
}
printf("%d",dp[c]);
return 0;
}
完全背包
有
N
件物品和⼀个最多能背重量为
W
的背包。第
i
件物品的重量是
w[i]
,得到的价值是
value[i]
。
每件物品都有⽆限个(也就是可以放⼊背包多次)
,求解将哪些物品装⼊背包⾥
物品价值总和最⼤。
与01背包的区别在于,遍历顺序
贴一下01背包
#include<bits/stdc++.h>
using namespace std;
int v[10000],w[10000];
int dp[10000];
int main()
{
int n,c;
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
for(int i=1;i<=n;i++)//填表
{
for(int j=c;j>=0;j--)//j必须从后面开始,这样dp[j]的改变才不会影响前面的dp
{
if(j>=w[i]&&dp[j-w[i]]+v[i]>dp[j])
{
dp[j]=dp[j-w[i]]+v[i];
}
}
}
printf("%d",dp[c]);
return 0;
}
j从后往前,保证了一种只加一次
j从前晚后,就实现了多次放入
难以理解就打印dp
P1616 疯狂的采药 https://www.luogu.com.cn/problem/P1616
#include<bits/stdc++.h>
using namespace std;
long long ti[10000+5],vi[10000+5];
long long dp[10000000+5];
int main()
{
int t,m;
scanf("%d%d",&t,&m);
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&ti[i],&vi[i]);
}
for(int i=1;i<=m;i++)
{
for(int j=0;j<=t;j++)
{
if(j>=ti[i]&&dp[j-ti[i]]+vi[i]>dp[j])
{
dp[j]=dp[j-ti[i]]+vi[i];
}
}
}
printf("%lld",dp[t]);
return 0;
}
另外, 背包问题的内外循环是可以调换的。