关于多重背包的优化问题。
首先多重背包很容易想到这样暴力转移:
for(int i=1;i<=n;i++)
{
for(int k=1;k<=a[i].num;k++)
{
for(int j=m;j>=a[i].v;j--)
{
dp[j]=max(dp[j],dp[j-a[i].v]+a[i].w);
}
}
}
但这个题是会T的。
于是,有了两种对多重背包的优化:分别是二进制拆分和单调队列优化。
一、二进制拆分:
把每种物品的数量拆分成二进制的形式,这样就可以在表示出所有数量的前提下,保证物品数最小。
证明略,具体代码如下:(非常好理解)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define ll long long
#define ui unsigned int
#define ull unsigned long long
#define R register
using namespace std;
namespace chu_xuan{
void swap(int &a,int &b){R int tmp=a;a=b,b=tmp;}
void read(int &a) {a=0;int b=1,c=getchar(); while(c>'9'||c<'0'){if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b;}
int In() {int a=0,b=1,c=getchar(); while(c>'9'||c<'0'){if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();return a*b;}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a>b?b:a;}
}using namespace chu_xuan;
const int N=1e6+5;
int n,m,f[N],v[N],w[N],cnt;
int main()
{
read(n);read(m);
for(int i=1,a,b,c;i<=n;++i)
{
read(a);read(b);read(c);
for(int j=1;j<=c;j<<=1)
{
v[++cnt]=j*a,w[cnt]=j*b;
c-=j;
}
if(c) v[++cnt]=a*c,w[cnt]=b*c;
}
for(int i=1;i<=cnt;i++)
{
for(int j=m;j>=w[i];j--)
{
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
}
cout<<f[m]<<'\n';
return 0;
}
二、单调队列优化:
待填坑