背包问题更深化的理解-多重背包的二进制拆分

这篇文章主要证明一下多重背包的二进制拆分的可行性与正确性:

类似于二进制的原理:一定可以表达一系列连续的正数,下面用例子证明

       把22进行二进制拆分:

         成为1,2,4,8,7;由1,2,4,8可以组成1--15之间所有的数,而对于16--22之间的数,可以先减去剩余的7,那就是1--15之间的数可以用1,2,4,8表示了。

例题:

NOI 8756:砝码称重V2

总时间限制: 
1000ms
内存限制: 
65536kB
描述

设有1g、2g、3g、5g、10g、20g的砝码各若干枚(其总重<=100,000),要求:计算用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况。

输入
一行,包括六个正整数a1,a2,a3,a4,a5,a6,表示1g砝码有a1个,2g砝码有a2个,……,20g砝码有a6个。相邻两个整数之间用单个空格隔开。
输出
以“Total=N”的形式输出,其中N为可以称出的不同重量的个数。
样例输入
1 1 0 0 0 0
样例输出
Total=3
提示 样例给出的砝码可以称出1g,2g,3g三种不同的重量。 注意:对于拆分剩余是0,因题目的意思要特别处理。
#include<iostream>
using namespace std;
#include<cstdio>
int a[]={0,1,2,3,5,10,20};
#define MAX 100100
bool f[MAX];
int val[MAX];
int t=0;
int sum=0;
void input()
{
    int count=0,b=0;
    for(int i=1;i<=6;++i)
    {
        scanf("%d",&b);
        sum+=b*a[i];
        count=a[i];
        if(b>1)
        {
            for(int i=1;i<=b;i<<=1)
            {
                ++t;
                val[t]=count*i;
                b-=i;
            }
            if(b>0)
            {
                ++t;
                val[t]=count*b;
            }
            continue;
        }
         
        if(b==1)
        {
            ++t;
            val[t]=count;
        }
    }
}
void DP()
{
    f[0]=true;
    for(int i=1;i<=t;++i)
      for(int j=sum;j>=val[i];--j)
      f[j]=f[j]||f[j-val[i]];/*注意val才是拆成的背包*/
    int p=0;
    for(int i=1;i<=sum;++i)
    if(f[i])
    p++;
    printf("Total=%d\n",p);
}
int main()
{
    input();
    DP();
    return 0;
}
View Code

 

  

转载于:https://www.cnblogs.com/c1299401227/p/5361718.html

很抱歉,由于我是一名语言模型AI,我并不具备直接运行代码的能力。但是,我可以为您提供一些关于多重背包二进制优化输入c代码的信息和建议。 多重背包问题是一种经典的动态规划问题,二进制优化是对传统多重背包算法的一种优化手段,可以大幅提升算法性能。 以下是一个可能的多重背包二进制优化输入c代码的基本框架: ```c #include <stdio.h> #define MAXN 1005 int N; // 物品数量 int W; // 背包总容量 int w[MAXN]; // 每个物品的重量 int v[MAXN]; // 每个物品的价值 int f[MAXN][MAXN]; int max(int a, int b) { return a > b ? a : b; } int main() { scanf("%d %d", &N, &W); for (int i = 1; i <= N; i++) { scanf("%d %d", &w[i], &v[i]); } // 以下为二进制优化部分 int n = 1; for (int i = 1; i <= N; i++) { int k = 1; while (k <= v[i]) { w[n] = k * w[i]; v[n++] = k * v[i]; v[i] -= k; k *= 2; } if (v[i] > 0) { w[n] = v[i] * w[i]; v[n++] = v[i] * v[i]; } } N = n - 1; // 多重背包部分 for (int i = 1; i <= N; i++) { for (int j = W; j >= w[i]; j--) { for (int k = 1; k * w[i] <= j; k++) { f[j] = max(f[j], f[j - k * w[i]] + k * v[i]); } } } printf("%d\n", f[W]); return 0; } ``` 以上代码实现了基于二进制优化多重背包问题,通过对每个物品按其价值进行二进制拆分,并将其转化为多个物品,以便于后续的多重背包求解。 需要注意的是,该算法的时间复杂度为 $O(NV\log V)$,其中 $V$ 为所有物品的总价值。如果您需要高效的算法实现,可以尝试其他优化技巧,如单调队列优化、有界背包优化等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值