验题人题解 | 火星背包 II
2024-09-09 21:23:37
发布于:上海
15阅读
0回复
0点赞
Sol 1
不难发现,题意就是 背包,用朴素的 背包方式维护即可。
准确地说,用 dp 维护,设 表示考虑前 个物品,重量不超过 的最大价值。
那么我们的决策其实只有第 个物品选/不选。
-
选
此时,重量会累计 ,价值会累计 。
考虑此时重量为 ,则选以前,重量是 。
所以 。
-
不选
此时的情况与 一摸一样,即 。
综上所述,dp 的状态转移方程就昭然若揭了,即
最后答案即为 。
时间复杂度、空间复杂度均为 。
期望得分 50 分
Sol 2
上面做法的瓶颈是 大(本题 可以达到 )时时间复杂度就会变得不可接受。
我们惊奇的发现, 和 的值域似乎很不同。
也就是说,就算所有东西都买上,总价值也只有 。
这时候可以想到 dp 的一种经典 trick,状态和目标函数转换。
也就是原来的方程 ,我们想成 。
也就是, 表示前 个物品,价值是 的最小重量。
与前面的决策讨论类似,具体讨论过程留给读者自己思考。
答案是最大的 使得 。
时间复杂度 ,空间复杂度 。此处 。
这时会 MLE。
我们发现 的决策,只依赖于上一行。也就是往前的两行三行四行都没有用了,可以不再记录。
采用 滚动数组 的方式进行记录,空间复杂度降为 。
如果不会滚动数组可以借鉴代码或者自行百度。
void solve(){
cin>>n>>m;
for(ll i=1;i<=n;i++){
cin>>w[i]>>v[i];
}
ll V=accumulate(v+1,v+1+n,0);
ll ans=0;
for(ll j=0;j<=V;j++) dp[0][j]=1e18;
dp[0][0]=0;
for(ll i=1;i<=n;i++){
for(ll j=0;j<=V;j++) dp[i&1][j]=dp[i&1^1][j];
for(ll j=v[i];j<=V;j++){
dp[i&1][j]=min(dp[i&1^1][j-v[i]]+w[i],dp[i&1][j]);
if(dp[i&1][j]<=m) ans=max(ans,j);
}
}
cout<<ans<<endl;
}
这里空空如也
有帮助,赞一个