题意:
有$n$种物品各有无限个,背包空间为$m$,第$i$种物品的体积为$a_i$,价值为$b_i$。求在不超过背包容量的前提下,取得的最大价值。
$n\le 10^6,\quad m\le 10^{16},\quad a_i,b_i\le 100$且均为正整数。
分析:
贪心一:实际上最多有$100\times 100=10^4$种物品,可以考虑去重,这样$n$的规模下降至$10^4$。
贪心二:如果两种物品的体积相同,我们肯定不会装价值更低的那种物品,这样$n$的规模下降至$100$。
转化法:由于$m$过于巨大,然而$a_i$相比较小,我们可以想到,性价比最优的物品一定会出现极多次,这样最终方案肯定可以分割成很多完全相同的小方案(全部装同一种物品),再在剩下的容量里精打细算。因此我们先做小容量(最大可支持的范围)的背包,再来组成最终方案。
综上,我们先做$n\le 100$,$m\le 2\times 10^5$的完全背包,设$f_i$表示背包容量为$i(1\le i \le 2\times 10^5)$时能取得的最大价值,则有$$f_m=\mathop{max}\limits_{i=1}^{2\times 10^5}\{\lfloor m/i \rfloor \times f_i + f_{m\%i}\}$$
实现(100分):
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define IL inline using namespace std; typedef long long LL; const int N=100; const int M=2e4; int n; LL m,w[103]; LL f[M+3]; int main(){ freopen("backpack.in","r",stdin); freopen("backpack.out","w",stdout); scanf("%d%lld",&n,&m); memset(w,0,sizeof w); for(int i=1;i<=n;i++){ LL x,y; scanf("%lld%lld",&x,&y); w[x]=max(w[x],y); } memset(f,0,sizeof f); for(int i=1;i<=N;i++) for(int j=i;j<=M;j++) f[j]=max(f[j],f[j-i]+w[i]); LL ans=0; for(int i=1;i<=M;i++) ans=max(ans,m/i*f[i]+f[m%i]); printf("%lld",ans); return 0; }
小结:
数据规模不同,造就不同题目。应学会灵活处理。