算法:多重背包问题dp

文章目录

    • 一、多重背包问题特点
      • 1.1、多重背包问题的特征
      • 1.2、解决多重背包问题的基本方法
        • 典型例题:AcWing——多重背包问题I
      • 1.3、二进制优化
        • 1.3.1、二进制优化的思想
        • 1.3.2、多重背包问题的二进制优化

在这里插入图片描述

一、多重背包问题特点

多重背包问题是背包问题的又一变种,它在0-1背包和完全背包问题的基础上增加了一个限制:每种物品i除了有一个重量w[i]和价值v[i]外,还有一个最大可用数量n[i]。这意味着每种物品i可以被选取的次数最多是n[i]次,而不是只有一次(0-1背包问题)或无限次(完全背包问题)。

1.1、多重背包问题的特征

  1. 有限的物品数量:每种物品有一个最大数量限制,不能无限制地选择。
  2. 背包容量限制:存在一个容量限制,所有选取的物品的总重量不能超过这个限制。
  3. 优化目标:目标是在不超过背包容量的前提下,最大化背包内物品的总价值。
  4. 复杂度:时间和空间复杂度取决于具体的实现方法,一般时间复杂度为O(V*sum(n[i]))

1.2、解决多重背包问题的基本方法

解决多重背包问题的基本思路是利用动态规划,其中最直观的方法是使用二维DP数组dp[i][j],表示考虑前i种物品,在不超过重量j的情况下的最大价值。和0-1背包问题的区别在于物品i能取n[i]次,因此状态转移方程可以写为:

for(int k=0;k<=n[i];++k)if(j-k*weight[i]>=0)dp[i][j]=max(dp[i][j],dp[i-1][j-k*weight[i]]+k*value[i]);

这里,k是从0n[i]的整数,表示选择第i种物品k次的可能性。

由于这种方法会导致较高的时间复杂度,时间复杂度为O(V*sum(n[i])),特别是当n[i]的值很大时,常常需要使用其他技巧。

典型例题:AcWing——多重背包问题I

AcWing:多重背包问题I
按照以上思路,并且按照0-1背包一样的思路,进行降维优化。

    for(int i=0;i<N;++i)for(int j=V;j>=volume[i];--j)for(int k=0;k<=n[i];++k)if(j-k*volume[i]>=0)dp[j]=max(dp[j],dp[j-k*volume[i]]+k*value[i]);

本题可以书写代码为:

#include<bits/stdc++.h>
using namespace  std;
int dp[101];
int main(void){ios_base::sync_with_stdio(false);cin.tie(0);int N,V;cin>>N>>V;vector<int> volume(N);vector<int> value(N);vector<int> n(N);for(int i=0;i<N;++i){cin>>volume[i]>>value[i]>>n[i];}for(int i=0;i<N;++i)for(int j=V;j>=volume[i];--j)for(int k=0;k<=n[i];++k)if(j-k*volume[i]>=0)dp[j]=max(dp[j],dp[j-k*volume[i]]+k*value[i]);cout<<dp[V];return 0;
}

1.3、二进制优化

1.3.1、二进制优化的思想

对于任何一个数,我们可以将其进行二进制拆分。即任何一个10进制数都能写成二进制数的形式。
比如:3=1+2=11B、10=2+8=1010B。

如果我们对于一个数,例如10,取出小于其的所有二进制位,即1B,10B,100B,1000B,那么我们必然能够选出其中的某些位来凑成10,并且对于小于10的任何一个正整数也可以被凑成,即选取其中若干位有:1B、10B、11B、100B、101B、110B、111B、1000B、1001B···。即,如果我们有一个物品,它能够被选择小于等于n次,我们可以通过选择其中的某些位来实现选择的所有情况。

那么我们把一个物品可以最多选择n次的问题,按照未优化的多重背包问题需要进行O(V*sum(n[i]))次计算取最大值 变成了
考虑在logn个物品中选择其中的某些物品,取最大值 的问题了。按到理来说,logn个物品要么被选要么不被选,一共是2的logn次方种情况,也就是n种情况;但是如果我们把这个问题转化成0-1背包问题,即利用动态规划来考虑,就变成了O(V*sum(logn[i]))次了。当n[i]<=2000时,logn[i]<=3.301,减少了一千倍计算量。

因此,我们对于n[i],可以进行二进制拆分,将n[i]个物品按照二进制拆分,变成若干堆,每次选择只能一次全选,这样使得我们需要考虑的物品变成logn[i]个,多重背包问题变成了一个0-1背包问题,即这logn[i]个物品,要么被选,要么不被选,能够取得的最大值。我们通过上述叙述可以知道logn[i]个物品的所有被选择的情况,刚好构成了0~n[i]中的所有数字。

由于一个物品的数量n不一定是2的整数倍,因此我们在考虑二进制的时候,因为我们的目的是凑成0~ n,因此我们在考虑二进制的时候,我们考虑到小于等于n/2位即可,它们能满足0~ k种情况(k<=n/2),然后剩余的n-k部分直接单独成一块就行,这样,能满足n-k~ k+n-k种情况,合并起来就是0~n中情况。

1.3.2、多重背包问题的二进制优化

通过二进制拆分,我们将m个物品每个最多选n[i]次的多重背包问题,转换成了 sum(logn[i])个物品的0-1背包问题。相当于进行了问题转换。

代码:

#include<bits/stdc++.h>
using namespace  std;
int dp[2002];
int main(void){ios_base::sync_with_stdio(false);cin.tie(0);int N,V;cin>>N>>V;vector<int> value;vector<int> volume;for(int i=0;i<N;++i){//构建二进制拆分物品int w,v,num;cin>>w>>v>>num;//w单物品体积,v单物品价值,num可选数量int s=num;int b=1;while(b<=s){//注意b必须是小于num,且不能是最高位 如1010B,b不能是1000Bvalue.push_back(b*v);volume.push_back(b*w);s-=b;b*=2;}if(s>0){value.push_back(s*v);volume.push_back(s*w);}}N=value.size();//更新物品数量for(int i=0;i<N;++i)for(int j=V;j>=volume[i];--j)dp[j]=max(dp[j],dp[j-volume[i]]+value[i]);cout<<dp[V];return 0;
}

位数关系即:

        int s=num;int b=1;num=log2(num);num=pow(2,num-1);while(b<=num){value.push_back(b*v);volume.push_back(b*w);s-=b;b*=2;}if(s>0){value.push_back(s*v);volume.push_back(s*w);}
        int s=num;int b=1;num=num>>1;while(b<=num){value.push_back(b*v);volume.push_back(b*w);s-=b;b*=2;}if(s>0){value.push_back(s*v);volume.push_back(s*w);}

官方:

#include<iostream>
using namespace std;const int N = 12010, M = 2010;int n, m;
int v[N], w[N]; //逐一枚举最大是N*logS
int f[M]; // 体积<Mint main()
{cin >> n >> m;int cnt = 0; //分组的组别for(int i = 1;i <= n;i ++){int a,b,s;cin >> a >> b >> s;int k = 1; // 组别里面的个数while(k<=s){cnt ++ ; //组别先增加v[cnt] = a * k ; //整体体积w[cnt] = b * k; // 整体价值s -= k; // s要减小k *= 2; // 组别里的个数增加}//剩余的一组if(s>0){cnt ++ ;v[cnt] = a*s; w[cnt] = b*s;}}n = cnt ; //枚举次数正式由个数变成组别数//01背包一维优化for(int i = 1;i <= n ;i ++)for(int j = m ;j >= v[i];j --)f[j] = max(f[j],f[j-v[i]] + w[i]);cout << f[m] << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/804607.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在Flutter应用中配置ipa Guard进行混淆

在移动应用开发中&#xff0c;保护应用代码安全至关重要。Flutter 提供了简单易用的混淆工具&#xff0c;帮助开发者在构建 release 版本应用时有效保护代码。本文将介绍如何在 Flutter 应用中使用混淆&#xff0c;并提供了相关的操作步骤和注意事项。 &#x1f4dd; 摘要 本…

彩虹聚合DNS管理系统源码

聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析&#xff0c;目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。本系统支持多用户&#xff0c;每个用户可分配不同的域名解析权限&#xff1b;支持API接口&#xff0c;支持获取域名…

LeetCode-冗余连接(并查集)

每日一题&#xff0c;今天又刷到一道使用并查集来解决的问题&#xff0c;再次加深了一遍自己对并查集的印象和使用。 题目要求 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1&#xff5e;n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1…

对象参数验证工具, 解决非controller层数据校验问题, @Validated、@Valid

工具类 package com.common;import com.common.SysException;import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import java.util.Set; import java.util.stream.Collectors;/**1. author: 0i773. Desc…

【计算机毕业设计】超市进销存管理系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

PostgreSQL入门到实战-第八弹

PostgreSQL入门到实战 PostgreSQL数据过滤(一)官网地址PostgreSQL概述PostgreSQL的where子命令介绍PostgreSQL的where子命令实操更新计划 PostgreSQL数据过滤(一) 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://ww…

数据结构---顺序表实现

目录 1.顺序表 2.动态顺序表的实现 &#xff08;4&#xff09;顺序表初始化 &#xff08;5&#xff09;顺序表销毁 &#xff08;6&#xff09;顺序表的插入 a.尾插 b.头插 &#xff08;7&#xff09;顺序表的删除 a.尾删 b.头删 &#xff08;8&#xff09;指定位置之…

大话设计模式之桥接模式

桥接模式是一种结构型设计模式&#xff0c;它将抽象部分与它的实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过提供一个桥接接口来实现这种分离&#xff0c;使得抽象部分和实现部分可以在运行时独立地进行修改。 桥接模式主要由两个部分组成&#xff1a;抽象部分…

Chat Ollama docker部署及运行 本地大语言模型+本地知识库搭建 强烈推荐

背景介绍 Ollama 是目前最流行的大模型本地化工具之一。 Ollama 支持一系列开源大模型&#xff0c;包括主流的聊天模型和文本嵌入模型&#xff08;Embedding Models&#xff09;等。 ChatOllama 是基于 Ollama 的 Web 应用&#xff0c;它可以让用户直接在浏览器中使用 Ollama。…

解锁电气数据新价值:SolidWorks Electrical助力企业转型

在信息化、数字化的时代&#xff0c;电气数据库已成为企业不可或缺的核心资产。它以其独特的功能和优势&#xff0c;助力企业在激烈的市场竞争中脱颖而出&#xff0c;实现数字化转型的跨越式发展。 SolidWorks Electrical电气数据库具备强大的数据整合能力。它能够将企业内部各…

Linux 学习之路 - 进程篇 - PCB介绍1-标识符

目录 一、基础的命令 <1> ps axj 命令 <2> top 命令 <3> proc 目录 二、进程的标识符 <1>范围 <2>如何获取标识符 <3>bash进程 三、创建进程 一、基础的命令 前面介绍了那么多&#xff0c;但是我们没有观察到进程相关状态&#x…

机器人码垛机的技术特点与应用

随着科技的飞速发展&#xff0c;机器人技术正逐渐渗透到各个行业领域&#xff0c;其中&#xff0c;机器人码垛机在物流行业的应用尤为引人瞩目。它不仅提高了物流效率&#xff0c;降低了成本&#xff0c;更在改变传统物流模式的同时&#xff0c;为行业发展带来了重大的变革。 一…

MQ死信队列:面试题

所谓的死信队列只不过是我们自己定义的一个队列&#xff0c;注意对于这个队列只能人工干预 面试题&#xff1a;你们是如何保证消息不会丢失的 1&#xff0c;什么是死信 在RabitMQ中充当主角的就是消息&#xff0c;在不同场景下&#xff0c;消息会有不同地表现。 死信就是在…

SpringBoot学习笔记三-原理分析

SpringBoot学习笔记三-原理分析 SpringBoot自动装配1.1 案例1.2 通过注解方式管理Bean1.3 小结1.4 Enable注解1.5 Import注解1.5.1 ImportSelector实现类1.5.2 导入ImportBeanDefinitionRegistrar 1.5 EnableAutoConfiguration1.6 案例 SpringBoot自动装配 当再pom.xml中导入对…

活动发布会新闻通稿如何写?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 撰写活动发布会的新闻通稿需要遵循一定的结构和内容要点&#xff0c;以确保信息的准确性、完整性和吸引力。以下是撰写活动发布会新闻通稿的基本步骤和建议&#xff1a; 标题&#xff1…

【智能算法】长鼻浣熊优化算法(COA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2023年&#xff0c;M Dehghani等人受到长鼻浣熊自然行为启发&#xff0c;提出了长鼻浣熊优化算法&#xff08;Coati Optimization Algorithm&#xff0c;COA&#xff09;。 2.算法原理 2.1算法思想…

C语言 函数——函数封装与程序的健壮性

目录 函数封装&#xff08;Encapsulation&#xff09; 如何增强程序的健壮性&#xff1f; 如何保证不会传入负数实参&#xff1f; 函数设计的基本原则 函数封装&#xff08;Encapsulation&#xff09; 外界对函数的影响——仅限于入口参数 函数对外界的影响——仅限于一个…

C++:内联函数inline,auto关键字,基于范围的for循环,nullpter

文章目录 1.内联函数 inline1.1 概念1.2查看方法1.3 特性1.4 题外话&#xff1a;宏 2.auto关键字2.1 auto 简介2.2 auto使用细则 3. 基于范围的for循环4. nullpter 1.内联函数 inline 1.1 概念 inline int Add(int x, int y) {return x y; } int main(){int ret 0;ret Add…

Vue input密码输入框自定义密码眼睛icon

我们用的饿了么UI组件库里,密码输入框的icon是固定不变的,如下所示: 点击"眼睛"这个icon不变,现在需求是UI给的设计稿里,密码输入框的"眼睛"有如下两种: 代码如下: <el-input:key="passwordType"ref="password"

重装系统前备份笔记

一、点查看自定义快捷键可以定义一些快速启动方式 然后用不习惯的快捷键也能在这里改 二、android studio 快捷键导出备份 导入方法&#xff1a; android studio &#xff0d;>file->import setting ->选择jar包即可 导出studio的设置方法&#xff1a; android …