【做题笔记】P2871 [USACO07DEC]手链Charm Bracelet

时间:2023-03-08 22:09:10

就是 01 背包。大意:给您 \(T\) 个空间大小的限制,有 \(M\) 个物品,第 \(i\) 件物品的重量为 \(c_i\) ,价值为 \(w_i\) 。要求挑选一些物品,使得总空间不超过 \(T\) ,且总价值最大。

考虑设 \(f_{i,j}\) 为 \(1\) ~ \(i\) 件物品,背包容量为 \(j\) 时的最大价值,那么假如不选第 \(i\) 件物品,则为 \(f_{i-1,j}\) 的子问题(背包内只有 \(i-1\) 个物品);若选,则为 \(f_{i-1,j-w_i}+v_i\) 的子问题。

#include <iostream>
#include <cstdio>
#include <cmath> using namespace std; int f[1001][1001],T,M,w[100001],v[100001]; int main()
{
cin>>T>>M;
for(int i=1;i<=M;i++)cin>>w[i]>>v[i];
for(int i=1;i<=M;i++)
for(int j=0;j<=T;j++)
if(j<w[i])f[i][j]=f[i-1][j];
else f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
cout<<f[M][T]<<endl;
return 0;
}

注意到这种做法本题会被卡。可以优化成一维,但过程很难想。

#include <iostream>
#include <cstdio>
#include <cmath> using namespace std; int f[1000001],T,M,w[1000001],v[1000001]; int main()
{
cin>>M>>T;
for(int i=1;i<=M;i++)cin>>w[i]>>v[i];
for(int i=1;i<=M;i++)
for(int j=T;j>=w[i];--j)
f[j]=max(f[j],f[j-w[i]]+v[i]);
cout<<f[T]<<endl;
return 0;
}