题意:
给出n件物品,每件物品有一个容量tit_{i}ti与价值viv_{i}vi,现有一个容量为mmm的背包,选出一个组合恰好塞满背包,并且使所有选择物品的异或和最大,输出这个异或和,若不存在这样的组合,输出-1
分析:
对这个01背包,可以用存在性dpdpdp,设dp[i][j]dp[i][j]dp[i][j]为容量为iii,已选取的物品的异或和为jjj是否可能存在,转移也非常简单dp[i][j]=dp[i−t[k]][j xor v[k]]dp[i][j]=dp[i-t[k]][j\ xor\ v[k]]dp[i][j]=dp[i−t[k]][j xor v[k]],但是这样枚举会超时,可以利用bitsetbitsetbitset节省时间,一个bitsetbitsetbitset可以看作一个boolboolbool数组,那么可以把bool dp[1100][1100]bool\ dp[1100][1100]bool dp[1100][1100]换成bitset<1100>dp[1100]bitset<1100>dp[1100]bitset<1100>dp[1100],bitsetbitsetbitset节省时间在利用左右移和整体赋值来达到节省时间。在这里,如果把原本dpdpdp数组的前后意义交换dp[i][j]dp[i][j]dp[i][j]表示为异或和为iii时,容量组合为jjj的组合是否存在,那么dp[i][j]=dp[i xor v[k]][j−t[k]]dp[i][j]=dp[i\ xor\ v[k]][j-t[k]]dp[i][j]=dp[i xor v[k]][j−t[k]],可以理解为,当前iii这一行的所有数都由i xor v[k]i\ xor\ v[k]i xor v[k]那一行对应位置的往前t[k]t[k]t[k]位转移过来,普通的boolboolbool数组不能左移,bitsetbitsetbitset可以,所以这里设bitset<1100>dp[1100],dp[i]bitset<1100>dp[1100],dp[i]bitset<1100>dp[1100],dp[i]意为异或和为iii的所有容量可能情况,那么dp[i]∣=dp[i xor v[k]]<<t[k]dp[i]|=dp[i\ xor\ v[k]]<<t[k]dp[i]∣=dp[i xor v[k]]<<t[k],右式的dpdpdp是计算完上一个物品的结果,因此在计算每一个物品时,需要保存前一个物品的结果。
总结一下:
bitsetbitsetbitset节省时间就在于整个数组左移右移后的整体赋值,发现本来的dpdpdp数组恰好某一行完全由另一行转移来,并且是每一个位置都是从那一列的对应位置的前kkk个位置转移来,也就是前一个符合了bitsetbitsetbitset整体赋值,后一个符合了bitsetbitsetbitset左移节省时间的特点,这样的情况是适合用bitsetbitsetbitset的
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read()
{
int ret=0,base=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') base=-1;
ch=getchar();
}
while(isdigit(ch))
{
ret=(ret<<3)+(ret<<1)+ch-48;
ch=getchar();
}
return ret*base;
}
int n,m,t[1100],v[1100];
bitset<1100>dp[1100],last[1100];
void work()
{
n=read();m=read();
for(int i=0;i<1024;i++) dp[i].reset();
for(int i=1;i<=n;i++)
{
t[i]=read();
v[i]=read();
}
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1023;j>=0;j--) last[j]=dp[j];
for(int j=1023;j>=0;j--) dp[j]|=last[j^v[i]]<<t[i];
}
int ans=-1;
for(int i=0;i<1024;i++)
{
if(dp[i][m]) ans=i;
}
cout<<ans<<endl;
}
int main()
{
int t=read();
while(t--) work();
return 0;
}
这篇博客介绍了如何使用动态规划结合Bitset优化解决01背包问题,其中物品具有容量和价值属性,目标是在背包容量限制下最大化物品的异或和。通过将状态转移方程与Bitset特性相结合,实现了高效的时间复杂度解决方案,避免了超时问题。文章详细阐述了Bitset在节省时间上的优势,并提供了完整的C++代码实现。
208

被折叠的 条评论
为什么被折叠?



