再次建议配合前文阅读:C++完全背包模板-CSDN博客
有 N 种物品和一个容量是 V 的背包。
第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
输出一个整数,表示最大价值。
0
4 5
1 2 3
2 4 1
3 4 3
4 5 2
10
题目看上去为01背包和完全背包的结合,实则难度更大,优化方式也不同。
照例,先写出无优化的代码
核心代码如下:
for (i=1;i<=n;i++)
{
for (k=1;k<=s[i];k++)
{
for (j=k*v[i];j<=V;j++)
{
f[i][j]=max(f[i-1][j],max(f[i-1][j-k*v[i]]+k*w[i],f[i][j-1]));
}
}
}
写法与完全背包大致相同,为不选,选,传递j-1的最大值,但是此时k有s[i]的限制
Ac代码如下:
#include
#include
using namespace std;
int f[1005][1005];
int v[1005],w[1005],s[1005];
int n,V;
int main ()
{
int i,j,k;
scanf("%d%d",&n,&V);
for (i=1;i<=n;i++) scanf("%d%d%d",&v[i],&w[i],&s[i]);
for (i=1;i<=n;i++)
{
for (k=1;k<=s[i];k++)
{
for (j=k*v[i];j<=V;j++)
{
f[i][j]=max(f[i-1][j],max(f[i-1][j-k*v[i]]+k*w[i],f[i][j-1]));
}
}
}
printf("%d",f[n][V]);
return 0;
}
我们可以将任何一个数写成由1和0组成的二进制数,也就是说,我们可以用二进制数组成一个数,如,我们可以用1(0001)2(0010)4 (0100)组成7(0111),那么我们是不是可以将某个物品的使用次数s[i]拆分成由二进制从小到大累加的数?
假如此时s[i]=7,那么我们可以拆成1+2+4,再将物品使用次数“捆绑”为一个新的物品,把1个物品看为体积为v[i],价值为w[i],把2个物品看为体积为2*v[i],价值为2*w[i],把4个物品看为体积为4*v[i],价值为4*w[i],再对它们进行完全背包的优化。
那如果某个数不能恰好由2^n组成的数呢,8(1000)不能从小到大被2^n的数累加,那么我们就将剩余的数再当作一个物品进行操作,我们将8拆成1 (0001)2 (0010)4 (0100)1(0001),此时就可以进行完全动态规划了
核心代码如下:
x=v[i]
y=v[i]
z=s[i]
cnt=0
for (i=1;i<=n;i++)
{
cin>>x>>y>>z;
for (j=1;j<=z;j*=2)
{
v[++cnt]=x*j;
w[cnt]=y*j;
z-=j;
}
if (z)
v[++cnt]=x*z,
w[cnt]=y*z;
}
n=cnt;
j循环2的倍数,将s[i]减去j,判断是否能再减去一个2的倍数
如果有剩余,将剩余的数捆绑为新的物品
注意:拆分后物品的总数应该为cnt而不是n
for (i=1;i<=n;i++)
{
for (j=m;j>=v[i];j--)
{
a[j]=max(a[j],a[j-v[i]]+w[i]);
}
}
倒序循环,因为我们已经将物品捆绑,不需要再重复累加,运用本轮的值,进行递推,与01背包相同
Ac代码如下:
#include
using namespace std;
int v[2005],w[2005],a[2005];
int n,m,cnt;
int main ()
{
int i,j;
int x,y,z;
cin>>n>>m;
for (i=1;i<=n;i++)
{
cin>>x>>y>>z;
for (j=1;j<=z;j*=2)
{
v[++cnt]=x*j;
w[cnt]=y*j;
z-=j;
}
if (z)
v[++cnt]=x*z,
w[cnt]=y*z;
}
n=cnt;
for (i=1;i<=n;i++)
{
for (j=m;j>=v[i];j--)
{
a[j]=max(a[j],a[j-v[i]]+w[i]);
}
}
int Max=-1;
for (i=1;i<=m;i++) Max=max(Max,a[i]);
cout<
成功Ac,完结撒花!
测试参考题目:P1757 通天之分组背包 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
(注意将输入输出,数组大小进行修改)
如有不解或优化,可在评论区留言
你可能感兴趣的:(c++,开发语言)