首页 > 编程语言 >[算法学习笔记] 多重背包--二进制拆分

[算法学习笔记] 多重背包--二进制拆分

时间:2023-08-03 16:55:21浏览次数:46  
标签:index 背包 -- 二进制 int 01 拆分

多重背包

回顾一下多重背包是什么?有\(n\)种物品,每个物品都有有限个,每个物品都有重量和价值两个参数,你有一个限重为\(W\)的背包,求背包内价值最大。

我们朴素的做法是将多重背包拆分成01背包求解,因为每个物品都有有限个,假设第\(i\)个物品有\(j\)个,那么跑\(j\)次01背包即可。

但是这样复杂度会很高,由于每次将多重背包拆分成\(j\)个独立的完全背包求解。在某些题目中会超时。

如何改善呢?

状态已经优化到了极致,无法处理。我们发现算法的瓶颈在于每次暴力的将一种物品拆分成\(j\)个,跑01背包。若改善算法只能从这里入手。

二进制拆分

首先一个性质,任何一个正整数都能表示成若干个二的整次幂的和的形式,例如\(2^0,2^1,2^2,2^3\)能表示从1-7的任意整数。

那么我们每次在将一种物品拆分成\(j\)个物品的时候是不是就可以只拆分成2的整次幂!因为只拆分成二的整次幂同样也可以不重不漏的表示。

若最后拆分不成二的整次幂,直接存就好。

将每种物品的\(w\)和\(v\)拆分完后,就可以直接当作01背包跑了。
二进制拆分参考代码如下:

	int a,b,m; //分别代表v,w,cnt,其中cnt为每种物品的个数
		read(a); //快读
		read(b);
		read(m);
		int c = 1;
		while(m > c) //完全背包的二进制拆分,将完全背包拆分成01背包 
		{
			m -= c;
			w[++index] = c*b;
			v[index] = c*a;
			c*=2;
		}
		w[++index] = m*b; //若最后拆分不成,直接存
		v[index] = m*a;

典例

Luogu P1776 宝物筛选

本题实际就是一个多重背包的板子,搭配二进制拆分即可AC

Code

//二进制拆分优化完全背包典型例题。待整 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 100000
#define INF 0x3f3f3f3f
using namespace std;
int n,W;
int w[N],v[N],cnt[N];
int f[N];
int maxn = -1;
template<typename type>
inline void read(type &x) //fast read 
{
    x=0;bool flag(0);char ch=getchar();
    while(!isdigit(ch)) flag=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    flag?x=-x:0;
}
template<typename type>
inline void write(type x,bool mode=1)//0为空格,1为换行 fast print 
{
    x<0?x=-x,putchar('-'):0;static short Stack[50],top(0);
    do Stack[++top]=x%10,x/=10; while(x);
    while(top) putchar(Stack[top--]|48);
    mode?putchar('\n'):putchar(' ');
}
int main()
{
//	freopen("input.txt","r",stdin);
	read(n);
	read(W);
	int index = 0;
	for(int i=1;i<=n;i++) 
	{
		int a,b,m;
		read(a);
		read(b);
		read(m);
		int c = 1;
		while(m > c) //完全背包的二进制拆分,将完全背包拆分成01背包 
		{
			m -= c;
			w[++index] = c*b;
			v[index] = c*a;
			c*=2;
		}
		w[++index] = m*b;
		v[index] = m*a;
	}
    for(int i=1;i<=index;i++)
    {
        for(int k = W;k>=w[i];k--)  //当01背包跑就好
		{
			f[k] = max(f[k],f[k-w[i]]+v[i]);
			maxn = max(maxn,f[k]);
		}
    }
    write(maxn,1);
	return 0;
}

标签:index,背包,--,二进制,int,01,拆分
From: https://www.cnblogs.com/SXqwq/p/17603794.html

相关文章

  • PlayWright(二十三)- allure插件(二)
    在上文中,我们认识了allure插件,并且也成功使用了,但是感觉少点东西,所以我们再深入挖掘下allure的功能  1.allure增加测试用例详情 1、导入allure模块2、在每条用例函数前加上@allure.title("标题内容")3、正常执行生成allure报告执行结果:2.allure增加测试用例描述用......
  • HTML总结笔记
    HTML总结学习来源:https://www.bilibili.com/video/BV1x4411V75C?p=11&vd_source=c406cec6bb9d5441fcb8903f9c8242d5基本标签<h1>一级标签</h1><h2>二级标签</h2><h3>三级标签</h3><h4>四级标签</h4><h5>五级标签</h5><h6>六级......
  • 【SpringBoot学习】2、idea 配置 SpringBoot 热启动详解,和热启动失效解决方案
    一、idea配置springboot热启动方法1、添加spring-boot-devtools的包,true必须加上。<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></d......
  • DevChat VSCode 插件安装配置指南
    PlaythisarticleYourbrowserdoesnotsupporttheaudioelement.SPEED1XTableofcontents快速路径 1.安装Python3环境(3.8或以上)2.安装插件3.设置AccessKey错误排查 1.运行时未就绪2.编码错误3.“可执行权限”......
  • Java后端02(jsp)
    jsp​ servlet是无法将后端获取的数据传递给html页面的,无法再servlet中通过转发或者是重定向的方式,给html页面传递响应的后端数据,servlet中由于拼接过于繁琐,是不适合写html的因此引入了jsp,既可以编写html标签,也可以写Java代码,<dependency><groupId>javax.serv......
  • playwright与cypress对比,各有什么优势与劣势
    Playwright和Cypress都是用于自动化测试的工具,但它们在一些方面有所不同。Playwright的优势:跨浏览器支持:Playwright支持多种浏览器,包括Chrome、Firefox和Safari等,可以在不同浏览器上运行测试,提高覆盖率。多语言支持:Playwright支持多种编程语言,包括JavaScript、Python和C#等,使......
  • 在DIALOG菜单栏里设置的全选(取消全选)或选择功能
     全选和取消全选: 选择和取消选择: ......
  • emoji符号大全
    本文转载自:Mr.曹的博客《一些常用的Emoji符号(可直接复制)》表情类......
  • Java后端03(浅谈注解)
    注解功能一:提示信息功能二:存储信息​ 注解需要定义注解类,类对象需要有落实的实体,注解可以出现在类Class上,方法Method上,成员变量Field上以及构造方法Constructor上,注解对象需要被添加注解的实体所对应的反射对象进行获取,人话:要获得注解信息,首先要获得修饰的东西的反射......
  • Excel中Hyperlink函数的使用
    Hyperlink函数是将文本形式的链接转换为超链接。调用格式:=HYPERLINK(链接,标题)或者:=HYPERLINK(链接)具体可参考Hyperlink函数Microsoft官方文档视频演示:......