背包问题-动态规划

news2024/11/26 16:39:53

 

背包问题

容量有限的背包,给很多商品,商品有相应的体积与价值

01背包问题

一个背包 每个物品只有一个

 

最终状态方程

dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])

推导过程

由上一层推导过来

选择拿不拿i

最终代码

#include<iostream>
#include<vector>
using namespace std;
// 1 2 3 4 5 分别代表商品编号
int bag_01(int n,int b,vector<int> &v,vector<int> &w)
{
    // b 代表bag v代表价值 w代表weight
    vector<vector<int>> dp(n+1,vector<int>(b+1));
    //int dp[v.size()+1][b+1]; // 代表选完i产品,背包有b容积 能获得的最大价值
    
    // 当i=0时
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=b;j++)
        {
            // 等于在背包容积允许的情况下给背包加了重量,同时也加入了价值
            dp[i][j]=dp[i-1][j];
            if(j>=w[i]) dp[i][j]=max(dp[i][j],dp[i-1][j-w[i]]+v[i]);
        }
    }
    return dp[n][b];
}

int main()
{
    // dp[i][j] i 表示第i次选择 j表示剩余的体积
    int n=0;
    cin>>n;
    vector<int> v(n+1);
    vector<int> w(n+1);
    int b=0;
    cin>>b;
    for(int i=1;i<=n;i++)
    {
        cin>>w[i]>>v[i];
    }
    cout<<bag_01(n,b,v,w)<<endl;
}

完全背包问题

每个商品无限个

 

最终状态方程

dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i])

推导过程

每个物品无限个,尝试为每个产品都尝试塞进去

for(int i=1;i<=n;i++)
{
	for(int j=0;j<=b;j++)
	{
			for(int k=0;j*w[i]<=j;k++)
			{
				dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
			}
	}
}

可以转化为2维,[i][j]中与[i][j-w[i]] 有很相似的部分

[i][j]=max([i-1][j],[i-1][j-w]+v,[i-1][j-2w]+2v,[i-1][j-3w]+3v....)
[i][j-w]=max([i-1][j-w],[i-1][j-2w]+v,[i-1][j-3w]+2v....). 
[i][j]=max([i-1][j],[i][j-w]+v)

最终代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int whole_bag(int n,int b,vector<int> &v,vector<int> &w)
{
    //cout<<"进入"<<endl;
    vector<vector<int> > dp(n+1,vector<int>(b+1));
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=b;j++)
        {
            dp[i][j]=dp[i-1][j];
            if(j>=w[i])
            {
                dp[i][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]);
            }
        }
    }
    return dp[n][b];
}
int main()
{
    int n=0;
    cin>>n;
    vector<int> v(n+1);
    vector<int> w(n+1);
    int b=0;
    cin>>b;
    for(int i=1;i<=n;i++)
    {
        cin>>w[i]>>v[i];
    }
    cout<<whole_bag(n,b,v,w)<<endl;
}

多重背包问题

每个物品数量不一样

 

推导过程

朴素解法,给k的数目加上一个限制

for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=b;j++)
        {
            for(int k=0;k*w[i]<=j&&k<=s[i];k++)
            {
                dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
            }
        }
    }

看能否采用完全背包的优化方法呢?

[i][j]=max([i-1][j],[i-1][j-w]+v,[i-1][j-2w]+2v,[i-1][j-3w]+3v+...+[i-1][j-sw]+sw)
[i][j-w]=max([i-1][j-w],[i-1][j-2w]+v,[i-1][j-3w]+2v....+[i-1][j-sw]+(s-1)w+[i-1][j-(s+1)w]+sw). 
会发现[i][j-w] 多了一项,这就无法用max

采用二进制方法优化,将 多重背包问题 转化成 01背包问题

如一个商品有100个

1 个 作为一个商品

2 个 作为一个商品

4 个 作为一个商品

8 个 作为一个商品

.. 最后一个商品用剩余的数目当成整体商品

512 个 作为一个商品

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int bag_01(int n,int b,vector<int>&w,vector<int>&v)
{
    vector<vector<int> > dp(n+1,vector<int>(b+1));
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=b;j++)
        {
            dp[i][j]=dp[i-1][j];
            if(j>=w[i]) dp[i][j]=max(dp[i][j],dp[i-1][j-w[i]]+v[i]);
        }
    }
    return dp[n][b];
}

int main()
{
    int n_fake=0;
    cin>>n_fake;
    int b=0;
    cin>>b;
    int n=0;
    vector<int> v;
    vector<int> w;
    v.push_back(-1);
    w.push_back(-1);
    for(int i=1;i<=n_fake;i++)
    {
        int l1,l2,l3;
        // l1 是 体积
        // l2 是 价值
        // l3 是 个数
        cin>>l1>>l2>>l3;
        int k=1;
        while(k>=l3)
        {
            l3-=k;
            v.push_back(l2*k);
            w.push_back(l1*k);
            n+=1;
            k*=2;
        }
        if(l3!=0)
        {
            v.push_back(l2*k);
            w.push_back(l1*k);
        }
    }
    cout<<bag_01(n,b,w,v)<<endl;

}

分组背包问题

 

物品有n组,每组物品有若干个,每组最多选一个

分组背包问题

dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i,k]]+v[i,k])

选择第k个商品

类似多重背包问题的朴素写法,非常符合逻辑


#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int group_bag(int n,int b,vector<vector<int> >& w,vector<vector<int> >& v)
{
    vector<vector<int> > dp(n+1, vector<int>(b+1));
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=b;j++)
        {
            dp[i][j]=dp[i][j-1];
            for(int l=0;l<v[i].size();l++)
            {
                if(w[i][l]<=j) dp[i][j]=max(dp[i][j],dp[i-1][j-w[i][l]]+v[i][l]);
            }
        }
    }
    return dp[n][b];
}
int main()
{
    vector<vector<int> > w;
    vector<vector<int> > v;
    int n=0;
    int b=0;
    cin>>n>>b;
    w.push_back(vector<int>(1));
    v.push_back(vector<int>(1));
    for(int i=1;i<=n;i++)
    {
        int n1=0;
        cin>>n1;
        vector<int> v1(n1);
        vector<int> w1(n1);
        for(int j=0;j<n1;j++)
        {
            int a=0;
            int b=0;
            cin>>a>>b;
            w1.push_back(a);
            v1.push_back(b);
        }
        w.push_back(w1);
        v.push_back(v1);
    }
    cout<<group_bag(n,b,w,v)<<endl;
}

欢迎大家 star ✨ GitHub - stolendance/acwing

正在更新算法模板   写上去就能用

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

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

相关文章

第12届蓝桥杯省赛真题剖析-2020年12月20日Scratch编程中级组

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第124讲。 第12届蓝桥杯省赛举办了两次&#xff0c;这是2020年10月20日举行的第一次省赛中级组试题&#xff0c;比赛仍…

【Java实战篇】Day6.在线教育网课平台

文章目录一、需求&#xff1a;绑定媒资1、需求分析2、库表设计与模型类3、接口定义4、Mapper层开发5、Service层开发6、完善controller层二、需求&#xff1a;课程预览1、需求分析2、实现技术3、模板引擎4、Freemarker入门5、部署网站门户6、接口定义7、接口开发8、编写模板9、…

放弃 console.log 吧!用 Debugger 你能读懂各种源码

很多同学不知道为什么要用 debugger 来调试&#xff0c;console.log 不行么&#xff1f; 还有&#xff0c;会用 debugger 了&#xff0c;还是有很多代码看不懂&#xff0c;如何调试复杂源码呢&#xff1f; 这篇文章就来讲一下为什么要用这些调试工具&#xff1a; console.lo…

PostgreSQL技术内幕(七)索引扫描

索引概述 数据库索引&#xff0c;是将一个表的某些字段的数据进行重新组织的数据库对象。通过使用索引&#xff0c;可以大大加速数据库的一些操作&#xff0c;其背后的思想也很简单朴素&#xff1a;空间换时间。 数据库中的索引&#xff0c;可以类比为一本书的目录&#xff0…

linux java中使用POI将word转为PDF时无法显示文字

背景: 在windos上本地调试时使用POI将word转为PDF时, PDF无法显示文字的原因以及解决方案: 我的是在linux7.9上&#xff0c;原因是生成world时候汉字正常&#xff0c;转pdf时没有汉字&#xff0c;多次调查后发现没有 宋体: 原因1:字体不存在问题, word中使用的字体在系统(wind…

udp 版本的 echo server 和 echo client

文章目录前言UDP数据报套接字编程什么是套接字套接字的api示例&#xff1a;一发一收&#xff08;无响应&#xff09;客户端服务端前言 基于udp socket写一个最简单的客户端服务器程序. UDP数据报套接字编程 什么是套接字 我们先来解释一下什么是套接字吧! 套接字&#xff0…

流浪地球2:AI人工智能+数字生命+元宇宙

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D开发工具链剧情介绍 太阳危机 太阳即将老化膨胀&#xff0c;吞没太阳系&#xff0c;地球上的人类构思了各种生存计划&#xff1a;其一是“数字生命计划”&#xff0c;该计划制造强大的量子计算机&#xff0c;希望让人类在数字世界…

D. Omkar and Circle(非常有意思的一道题)

Problem - D - Codeforces 丹尼是当地的数学狂人&#xff0c;他对圆形很着迷&#xff0c;这是奥姆卡最近的发明。帮他解决这个圆的问题!已知n个非负整数a1, a2&#xff0c;&#xff0c; an&#xff0c;它们排成一个圆&#xff0c;其中n必须是奇数。n -1能被2整除)。形式上&…

基于Tensorflow搭建卷积神经网络CNN(人脸识别)保姆及级教程

项目介绍 TensorFlow2.X 搭建卷积神经网络&#xff08;CNN&#xff09;&#xff0c;实现人脸识别&#xff08;可以识别自己的人脸哦&#xff01;&#xff09;。搭建的卷积神经网络是类似VGG的结构(卷积层与池化层反复堆叠&#xff0c;然后经过全连接层&#xff0c;最后用softm…

KD-2125地下电缆测试仪

一、产品概述 管线探测仪是一套高性能地下金属管线探测系统&#xff0c;由信号发射机和接收机组成&#xff0c;可用于金属管线、地下电缆的路径探测、管线普查和深度测量&#xff0c;配合多种选配附件&#xff0c;可以进行唯一性鉴别&#xff0c;以及管道绝缘破损和部分类型电缆…

HTML—javaEE

文章目录1.认识HTML2.HTML标签的使用2.1注释2.2标题2.3段落2.4换行2.5字体加粗、斜体字、删除线、下划线2.6图片2.7超链接2.8表格2.9列表2.10表单标签2.11div2.12span3.HTML特殊符号1.认识HTML &#xff08;1&#xff09;HTML是网页的编程语言&#xff0c;文件的内容主要由“标…

【从零开始学Skynet】实战篇《球球大作战》(十一):战斗场景设计

现在的服务端框架有支撑数万玩家的能力&#xff0c;且支持横向拓展&#xff08;即 增加物理机数量&#xff09;&#xff0c;理论上具有无上限的负载能力。下面以《球球大 作战》为例&#xff0c;说明怎样使用这套框架。1、战斗流程 玩家登录后&#xff0c;玩家可以做些非战斗操…

形式语言和自动机总结DFA、NFA

第一章DFA 形式定义和状态转移函数: DFA是一种特殊的NFA&#xff0c; A{Q,,,,F} Q:输入状态集&#xff0c;∑:字母表&#xff0c;δ:状态转移函数Q∑→Q q0∈Q初始状态 F终结集 设计举例 1.设计接受偶数个0和偶数个1串的DFA 2.设计 DFA 接受 {0,1} 上的字符串 w, 且 w 是 …

C++之模拟实现map和set

文章目录前言一、迭代器1.begin()和end()2.operator()二、改造红黑树三、map的模拟实现四、set的模拟实现总结前言 基于之前的红黑树和map、set的相关知识&#xff0c;本节我们使用红黑树来模拟实现STL中的map和set。 一、迭代器 使用迭代器可以方便我们对数据结构进行遍历&a…

windows安装wsl2

总的来说是按照这三个链接来的&#xff0c;也写了一个大体流程。 wsl对win版本有要求&#xff0c;可以 winr winver查看 原始参考链接&#xff1a; 1&#xff09;https://zhuanlan.zhihu.com/p/466001838 2&#xff09;https://cloud.tencent.com/developer/article/1986728 3&…

SpringCloud之Eureka、Ribbon及Nacos

SpringCloud之Eureka、Ribbon及Nacos 文章目录SpringCloud之Eureka、Ribbon及Nacos1. 单体架构和微服务架构2. SpringBoot、SpringCloud及SpringCloud Alibaba之间的版本对应关系2022.x 分支2021.x 分支2.2.x 分支组件版本关系3. Eureka3.1 Eureka-server注册中心3.2 Eureka-cl…

Elasticsearch:使用 ingest pipeline 来管理索引名称

在我之前的文章 “Elasticsearch&#xff1a;使用 pipelines 路由文档到想要的 Elasticsearch 索引中去” 我详述了如何使用已有的 date_index_name 处理器来把文档归类到所需要的和文档日期相关的的索引中去。比如&#xff0c;我们想把 2023 年 4 月的所有文档写入到 my-index…

【QT】MainWindow中如何为菜单栏或工具栏中的Menu或Action设置快捷键

目录1. 设置快捷键的两种方法1.1 在控件title属性的某个字母前加上&&#xff0c;&#xff08;Alt该字母&#xff09;作为快捷键1.2 使用 setShortcuts,&#xff08;Ctrl字母&#xff09;作为快捷键2. 为菜单栏中的 menu 设置快捷键2.1 测试2.2 代码3. 为菜单栏或工具栏中的…

百兆以太网使用的电信号编码分析

以太网是一种计算机局域网的组网技术。在IEEE制定的IEEE 802.3标准给出了以太网的技术标准。它规定了包括物理层的连线、电信号和介质访问层协议的内容。以太网是当前应用普遍的局域网技术。它很大程度上取代了其他局域网标准&#xff0c;如令牌环、FDDI和ARCNET。 我们常见的网…

Netty通信技术进阶一

Netty通信技术进阶1. 概念2. 线程同步、异步3. 其他通信技术对比4. Netty中的Reactor实现5. Pipeline 和 Handler5.1 ChannelHandler 分类6. 入站事件传播7.inbound/outbound 加载顺序和执行顺序8. 出站事件传播9. Code example9.1 编写服务端9.2 编写客户端10. 核心组件10.1 B…