多重背包模板题题解&学习笔记
1. 学习笔记
1.1 算法介绍
多重背包是告诉你有多少个物体重量以及价值,并且每种物品还外加了最多能取多少个。问你最大能凑出的价值。
1.2 算法流程
$$多重背包暴力做法$$
这个看过 完全背包 的同学应该不难想到,直接三重循环枚举空间和个数就好了。
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int dp[N][N];
int v[N],w[N],c[N];
int main()
{
int n,m;
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++) scanf("%d%d%d",&v[i],&w[i],&c[i]);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)//枚举空间
{
for(int k=0;k<=c[i] && k*v[i]<=j;k++) dp[i][j]=max(dp[i][j],dp[i-1][j-k*v[i]]+w[i]*k);//枚举当前要选几遍当前物品
}
}
printf("%d",dp[n][m]);
}
$$多重背包二进制优化$$
大家记不记得小学奥数中有一道题?
小明有1~13克的砝码$13$个,请问最少要选其中多少个砝码才能称出1~13克中的所有重量?
这道小学奥数题不仅可以一个一个试,还可以用二进制。
我们只需要选$1$,$2$,$4$,$8$…这样一个一个选过去就好了
为什么?
首先,$1$可以凑出$1$
$1,2$可以凑数1~3
那么$1,2,4$就可以凑出1~7
因为为1~3可以凑出来了,$4$有单独了,所以可以。而5~7就相当于是凑出$4$加$1$或$2$或$1+2$。
接下来看$1,2,4,8$ 1~8可以凑出来了 凑出9~15分两种情况
凑出9~11 就相当于凑出$8$加上$1$和$2$的所有相加组合
凑出12~15相当于凑出$8$加$4$加$1$和$2$的所有相加组合
那么以此类推,每想凑出从当前数到下一项之间的所有数。就相当于当前项加上所有之前项的所有相加组合。
会不会感觉有点晕?看图:
我们只需要要将判断当前物品可选的次数拆解成$ 1* w[i] ,2 * w [i] ,4 * w[i]… $这样打包。再做一遍$01$背包就能得出答案了。因为根据上面的结论,二进制可以凑出 所有情况下的数,那么也自然可以凑出选了每个遍数的物体。
那么只要按照上述内容将一个物体按照能选的遍数二进制差分当成多个物体,然后做一遍$01$背包问题就迎刃而解了。(点个关注+赞吧我写到这起码花了一个小时)
2. 模板题题解
暴力枚举
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int dp[N][N];
int v[N],w[N],c[N];
int main()
{
int n,m;
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++) scanf("%d%d%d",&v[i],&w[i],&c[i]);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)//枚举空间
{
for(int k=0;k<=c[i] && k*v[i]<=j;k++) dp[i][j]=max(dp[i][j],dp[i-1][j-k*v[i]]+w[i]*k);//枚举当前要选几遍当前物品
}
}
printf("%d",dp[n][m]);
}
二进制优化
#include <bits/stdc++.h>
using namespace std;
const int N = 20010;
int dp[N];
int w[N],v[N];
int cnt=0;
int main()
{
int n,m;
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++)
{
int a,s,c;
scanf("%d%d%d",&a,&s,&c);
int k=1;
while(k<=c)
{
cnt++;
v[cnt]=a*k;//二进制差分,将v*k当成完整的一个物品使用
w[cnt]=s*k;
c-=k;
k*=2;
}
if(c>0)//如果c减到剩下还有余话还得再打包,因为这说明二进制差分后还有余,不加上话c这个数凑不出来
{
cnt++;
v[cnt]=a*c;
w[cnt]=s*c;
}
}
for(int i=1;i<=cnt;i++)
{
for(int j=m;j>=v[i];j--) dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
}
printf("%d",dp[m]);
}
写到这已经有气无力了,给个关注+赞吧,有什么说的不对的欢迎指出来!!