背包总结(未完待续)
1.定义
泛化物品是指该物品的价值与其体积存在一一对应的关系,即该物品的价值随着体积的变化而变化,是一种函数关系。
例如,在01背包中,最后的答案数组其实就是一个泛化物品。
2运算
2.1 泛化物品的并
有泛化物品\(f,g\),他们的并是相同体积下价值的最大值。设f体积为fv,g体积为gv,把并后的泛化物品重新赋值给f
代码:
int v=Max(fv,gv);
for(int i=1;i<=v;i++) f[i]=Max(f[i],g[i]);
2.2泛化物品与普通物品的合并
此过程类似于01背包,f为泛化物品,fv为其最大体积,v,c分别为普通物体的体积,价值。
代码:
for(int i=1;i<=fv;i++) f[i+v]=Max(f[i+v],f[i]+c);
2.3 泛化物品与泛化物品的合并
此过程要枚举当前的总体积,和分给第一个泛化物品的体积,结果取最值。
设f,g两个泛化物品的合并为h,fv,gv定义如上。
代码:
for(int i=0;i<=v;i++)
for(int j=0;j<=i;j++)
h[i]=Max(h[i],g[j]+f[i-j]);
3例题
3.1 分组背包
http://ybt.ssoier.cn:8088/problem_show.php?pid=1272
可以发现,每一组中其实都是一个泛化背包,价值随着体积的变化而变化。
把一个组转化为一个泛化背包只有一点需要注意,如果体积有剩余,价值与前面的一样。详细看代码。
转换完之后,对n个泛化背包进行合并。输出结果。有了泛化背包这个概念后明显好理解了许多。
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<deque>
#include<cstdlib>
#include<ctime>
#define dd double
#define ll long long
#define ull unsigned long long
#define N 11
#define M 201
using namespace std;
int v,n,t;
int h[N][M];
inline int Max(int a,int b){
return a>b?a:b;
}
int main(){
scanf("%d%d%d",&v,&n,&t);
for(int i=1;i<=n;i++){
int w,c,p;
scanf("%d%d%d",&w,&c,&p);
h[p][w]=Max(h[p][w],c);
}
for(int i=1;i<=t;i++){
int now=0;
for(int j=0;j<=v;j++){
now=Max(now,h[i][j]);
h[i][j]=now;
}
}
// for(int i=1;i<=t;i++){
// for(int j=0;j<=v;j++) printf("%d ",h[i][j]);
// printf("\n");
// }
for(int i=2;i<=t;i++){
for(int j=v;j>=0;j--)
for(int k=0;k<=j;k++)
h[i][j]=Max(h[i][j],h[i-1][k]+h[i][j-k]);
// printf("new i:%d ",i);
// for(int j=0;j<=v;j++) printf("%d ",h[i][j]);
// printf("\n");
}
printf("%d",h[t][v]);
return 0;
}
3.2 01背包
http://ybt.ssoier.cn:8088/problem_show.php?pid=1267
for(int i=1;i<=n;i++)
{
int w,c;
scanf("%d%d",&w,&c);
for(int j=m;j>=w;j--)
{
f[j]=max(f[j],f[j-w]+c);
}
}
3.3完全背包
http://ybt.ssoier.cn:8088/problem_show.php?pid=1268
for(int i=1;i<=n;i++)
{
int w,c;
scanf("%d%d",&w,&c);
for(int j=w;j<=m;j++)
{
f[j]=max(f[j],f[j-w]+c);
}
}
3.4混合背包
http://ybt.ssoier.cn:8088/problem_show.php?pid=1270
for(int i=1;i<=n;i++)
{
int w,c,p;
scanf("%d%d%d",&w,&c,&p);
if(p==1) a[++tail].intt(w,c,1);
else if(p==0) a[++tail].intt(w,c,0);
else
{
for(int j=1;j<=p;j*=2)
{
p-=j;
a[++tail].intt(j*w,j*c,1);
}
if(p) a[++tail].intt(p*w,p*c,1);
}
}
for(int i=1;i<=tail;i++)
{
if(a[i].p==1)
for(int j=m;j>=a[i].w;j--)
f[j]=max(f[j],f[j-a[i].w]+a[i].c);
else
for(int j=a[i].w;j<=m;j++)
f[j]=max(f[j],f[j-a[i].w]+a[i].c);
}
未完待续。