[HNOI2007]梦幻岛宝珠(背包)

本文深入解析了一种称为神仙背包的算法,该算法用于解决在给定的重量限制下,从一系列具有特定重量和价值的宝石中选择组合以最大化总价值的问题。通过二进制位DP方法,文章详细阐述了如何从低到高处理每一位,以及如何进行复杂的合并操作。代码示例展示了如何实现这一算法,包括初始化数据结构、处理每一层物品以及更新动态规划状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给你N颗宝石,每颗宝石都有重量和价值。要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值。数据范围:N<=100;W<=2^30,并且保证每颗宝石的重量符合a*2^b(a<=10;b<=30)

Solution

神仙背包。

我们可以先对每个二进制位dp一下,然后从低到高位依次处理。

合并操作比较麻烦。

假设我们有一个容量为j的背包,我们要从上一层拿容量为k的物品,那么我们上一层需要的大小为k*2+(w>>i-1)&1,后面的是要满足w的二进制位,前面的是要贡献上去。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 32
using namespace std;
int dp[N][1002],e[N][102],val[N][102],ji[N],sum[N],n,w,ww,v,ans;
const int ma=1000;
int main(){
    while(1){
        scanf("%d%d",&n,&w);
        if(n<0)break;
        memset(dp,0,sizeof(dp));memset(e,0,sizeof(e));memset(val,0,sizeof(val));
        memset(ji,0,sizeof(ji));memset(sum,0,sizeof(sum));
        ans=0;
        for(int i=1;i<=n;++i){
            scanf("%d%d",&ww,&v);
            for(int j=30;j>=0;--j)
              if(ww%(1ll<<j)==0){
                e[j][++ji[j]]=ww/(1ll<<j),sum[j]+=ww/(1ll<<j),val[j][ji[j]]=v;
                break;
               }
        }
        for(int o=0;o<=30;++o)
          for(int i=1;i<=ji[o];++i)
            for(int j=sum[o];j>=e[o][i];--j)
              dp[o][j]=max(dp[o][j],dp[o][j-e[o][i]]+val[o][i]);
        for(int i=1;i<=30;++i){
          sum[i]+=(sum[i-1]+1)/2;
          for(int j=sum[i];j>=0;--j)
            for(int k=0;k<=j;++k){
              dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[i-1][min(sum[i-1],2*k+((w>>i-1)&1))]); 
           }
         }
        printf("%d\n",dp[30][0]);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/ZH-comld/p/9818356.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值