PS:这应该是我有史以来写的字最少的一篇题解blog了╰( ̄▽ ̄)╭2333,发个模板留着用。
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 钻石 Diamond
题目描述 Description
背包体积为V ,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取mi件(mi > 1) , 要么数量无限 , 在所装物品总体积不超过V的前提下所装物品的价值的和的最大值是多少?
输入描述 Input Description
第一行两个数N,V,下面N行每行三个数Vi,Wi,Mi表示每个物品的体积,价值与数量,Mi=1表示至多取一件,Mi>1表示至多取Mi件,Mi=-1表示数量无限
输出描述 Output Description
1个数Ans表示所装物品价值的最大值
样例输入 Sample Input
2 10
3 7 2
2 4 -1
样例输出 Sample Output
22
数据范围及提示 Data Size & Hint
对于100%的数据,V <= 200000 , N <= 200
i:当前处理的物品 。 j:加上当前物品后达到体积j的最大价值。
满足最优性和无后效性。
*01背包:
if(j>=v[i]) f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]) ;
else f[i][j]=f[i-1][j];
优化一维:
for(int i=1;i<=N;++i)
for(int j=V;j>=v[i];--j) //!
f[j]=max(f[j],f[j-v[i]]+w[i]);
*完全背包
1.过滤掉w[i] < w[j] && v[i] > v[j]的物品 + 二进制拆分成01背包。
2.01背包的一维优化中把j反过来枚举。
*多重背包
二进制拆分成01背包。
二进制拆分: 自己打的 ,不知道具体怎么样打(*/ω\*)。
思想:把n分解为1+2+4+8+…+k。(=x)由于可能不能恰好分解,剩下的n-x如果在前面有相同的,就把相同的-1,n-x+1.
void Done_many(int v,int w,int m)
{
int k=1,x=0;
memset(a,0,sizeof(a));
while(m)
{
if(m-k>=0) a[++x]=k,m-=k;
else break;
k*=2;
}
if(m>1) {
int i=1; while(a[i]!=m&&i!=x+1) ++i; if(i<=x) --a[i],++a[x+1]; a[++x]+=m;
}
if(m==1) a[++x]=m;
for(int i=1;i<=x;++i)
Build(v*a[i],w*a[i],1);
}
代码
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int V,N,v,w,c,m,Cnt,cnt;
int f[200050],a[65000];
struct maple{
int v,w,m;
}thing[100050];
void Build(int v,int w,int m)
{
thing[++cnt]=(maple){ v,w,m };
}
void Done_many(int v,int w,int m)
{
int k=1,x=0;
memset(a,0,sizeof(a));
while(m)
{
if(m-k>=0) a[++x]=k,m-=k;
else break;
k*=2;
}
if(m>1) {
int i=1; while(a[i]!=m&&i!=x+1) ++i; if(i<=x) --a[i],++a[x+1]; a[++x]+=m;
}
if(m==1) a[++x]=m;
for(int i=1;i<=x;++i)
Build(v*a[i],w*a[i],1);
}
int main()
{
scanf("%d%d",&N,&V);
for(int i=1;i<=N;++i)
{
scanf("%d%d%d",&v,&w,&m);
if(m>1) Done_many(v,w,m);
else Build(v,w,m);
}
for(int i=1;i<=cnt;++i)
{
if(thing[i].m==1)
for(int j=V;j>=thing[i].v;--j)
f[j]=max(f[j],f[j-thing[i].v]+thing[i].w);
else
for(int j=thing[i].v;j<=V;++j)
f[j]=max(f[j],f[j-thing[i].v]+thing[i].w);
}
cout<<f[V];
return 0;
}