HDU2022多校第一场C,bitset优化bool dp

这篇博客介绍了如何使用动态规划结合Bitset优化解决01背包问题,其中物品具有容量和价值属性,目标是在背包容量限制下最大化物品的异或和。通过将状态转移方程与Bitset特性相结合,实现了高效的时间复杂度解决方案,避免了超时问题。文章详细阐述了Bitset在节省时间上的优势,并提供了完整的C++代码实现。
摘要由CSDN通过智能技术生成
题意:

给出n件物品,每件物品有一个容量 t i t_{i} ti与价值 v i v_{i} vi,现有一个容量为 m m m的背包,选出一个组合恰好塞满背包,并且使所有选择物品的异或和最大,输出这个异或和,若不存在这样的组合,输出-1

分析:

对这个01背包,可以用存在性 d p dp dp,设 d p [ i ] [ j ] dp[i][j] dp[i][j]为容量为 i i i,已选取的物品的异或和为 j j j是否可能存在,转移也非常简单 d p [ i ] [ j ] = d p [ i − t [ k ] ] [ j   x o r   v [ k ] ] dp[i][j]=dp[i-t[k]][j\ xor\ v[k]] dp[i][j]=dp[it[k]][j xor v[k]],但是这样枚举会超时,可以利用 b i t s e t bitset bitset节省时间,一个 b i t s e t bitset bitset可以看作一个 b o o l bool bool数组,那么可以把 b o o l   d p [ 1100 ] [ 1100 ] bool\ dp[1100][1100] bool dp[1100][1100]换成 b i t s e t < 1100 > d p [ 1100 ] bitset<1100>dp[1100] bitset<1100>dp[1100] b i t s e t bitset bitset节省时间在利用左右移和整体赋值来达到节省时间。在这里,如果把原本 d p dp dp数组的前后意义交换 d p [ i ] [ j ] dp[i][j] dp[i][j]表示为异或和为 i i i时,容量组合为 j j j的组合是否存在,那么 d p [ i ] [ j ] = d p [ i   x o r   v [ k ] ] [ j − t [ k ] ] dp[i][j]=dp[i\ xor\ v[k]][j-t[k]] dp[i][j]=dp[i xor v[k]][jt[k]],可以理解为,当前 i i i这一行的所有数都由 i   x o r   v [ k ] i\ xor\ v[k] i xor v[k]那一行对应位置的往前 t [ k ] t[k] t[k]位转移过来,普通的 b o o l bool bool数组不能左移, b i t s e t bitset bitset可以,所以这里设 b i t s e t < 1100 > d p [ 1100 ] , d p [ i ] bitset<1100>dp[1100],dp[i] bitset<1100>dp[1100]dp[i]意为异或和为 i i i的所有容量可能情况,那么 d p [ i ] ∣ = d p [ i   x o r   v [ k ] ] < < t [ k ] dp[i]|=dp[i\ xor\ v[k]]<<t[k] dp[i]=dp[i xor v[k]]<<t[k],右式的 d p dp dp是计算完上一个物品的结果,因此在计算每一个物品时,需要保存前一个物品的结果。

总结一下:

b i t s e t bitset bitset节省时间就在于整个数组左移右移后的整体赋值,发现本来的 d p dp dp数组恰好某一行完全由另一行转移来,并且是每一个位置都是从那一列的对应位置的前 k k k个位置转移来,也就是前一个符合了 b i t s e t bitset bitset整体赋值,后一个符合了 b i t s e t bitset bitset左移节省时间的特点,这样的情况是适合用 b i t s e t bitset bitset

#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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值