动态规划(一):01背包问题和完全背包问题

news2024/9/25 9:34:50

动态规划

目录

  • 动态规划
    • 1.01背包问题
      • 1.1题目介绍
      • 1.2思路一介绍(二维数组)
      • 1.3思路二介绍(一维数组) ==空间优化==
      • 1.4思路三介绍(输入数据优化)
    • 2.完全背包问题
      • 2.1题目描述:
      • 2.2思路一(朴素算法)
      • 2.3思路二(将k优化处理掉)
      • 2.4思路三(优化j的初始条件)
    • 总结

1.01背包问题

1.1题目介绍

在这里插入图片描述

1.2思路一介绍(二维数组)

在这里插入图片描述

代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
 const int N=1010;
 int v[N],w[N]; //v[N]是物品体积 w[N]是物品的价值
 int f[N][N]; //f[i][j]在体积不超j的前提下,从i个物品中选择最大值
 int main()
 {
     int n,m;
     cin>>n>>m;
     for(int i=1;i<=n;i++)
     {
         cin>>v[i]>>w[i];
     }
     for(int i=1;i<=n;i++)
     {
         for(int j=1;j<=m;j++)
         {
             f[i][j]=f[i-1][j];
             if(j>=v[i])//如果我们的背包容量j大于第i个物品的体积,我们在进行决策是否加入第i个物品
             f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
         }
     }
     cout<<f[n][m]<<endl;
     return 0;
 }

1.3思路二介绍(一维数组) 空间优化

为什么可以使用一维数组?

我们先来看一看01背包问题的状态转移方程,我们可以发现 f[i]只用到了f[i-1],其他的是没有用到的,我们可以用滚动数组来做。

还有一个原因就是我们在计算f[i] [j]的时候我们只用到了f[i-1] [j]和f[i-1] [j-v[i]],其中j和j-v[i]都是小于等于j的,在j的同一侧,所以我们综合以上两点原因就可以将二维优化到一维,即完成空间优化。

在这里插入图片描述

我们先来将二维和优化后的一维在关键算法代码上进行一下对比:

for(int i = 1; i <= n; i++) 
    for(int j = m; j >= 0; j--)
    {
        if(j < v[i]) 
            f[i][j] = f[i - 1][j];  // 优化前
            f[j] = f[j];            // 优化后,该行自动成立,可省略。
        else    
            f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);  // 优化前
            f[j] = max(f[j], f[j - v[i]] + w[i]);                   // 优化后
    }

实际上,只有当枚举的背包容量 >= v[i] 时才会更新状态,因此我们可以修改循环终止条件进一步优化。

for(int i=1;j<=n;i++)
{
	for(int j=m;j>=v[i];j--)
	{
		f[j]=max(f[j],f[j-v[i]]+w[i]);
	}
}

在这里插入图片描述

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m;
int v[N], w[N];
int f[N];

int main()
{
    cin >> n >> m;

    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];

    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;
}

1.4思路三介绍(输入数据优化)

我们注意到在处理数据时,我们是一个物品一个物品,一个一个体积的枚举。

因此我们可以不必开两个数组记录体积和价值,而是边输入边处理。

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 1005;
int f[MAXN];  // 

int main() 
{
    int n, m;   
    cin >> n >> m;

    for(int i = 1; i <= n; i++) {
        int v, w;
        cin >> v >> w;      // 边输入边处理
        for(int j = m; j >= v; j--)
            f[j] = max(f[j], f[j - v] + w);
    }

    cout << f[m] << endl;

    return 0;
}

2.完全背包问题

2.1题目描述:

在这里插入图片描述
在这里插入图片描述

2.2思路一(朴素算法)

#include<iostream>
using namespace std;
const int N=1010;
int f[N][N];
int n,m;
int v[N],w[N];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=m;j++)
        {
            for(int k=0;k*v[i]<=j;k++)
            {
                f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
            }
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}

上述朴素算法和01背包问题的朴素算法非常相似,但是会超时。所以我们接下来就会对这个算法进行优化处理。

2.3思路二(将k优化处理掉)

在这里插入图片描述

我们先来分析一下状态转移方程,我们发现方程一和方程二有一定的联系,我们先不看方程一红色圈出来的部分,我们比较方程一黄色的部分和方程二的内容,我们发现方程一就是比方程二每一项多了一个w,那么我们黄色圈出来的部分的最大值也就比方程二的最大值多w,那么我们其实就可以将方程一圈出来黄色的部分进行等价替换,替换成红色方框黄色字体的内容,我们最终得出最下方的结论,其实我们要求得最大值之和两个状态有关,比较它们的最大值即可。

我们发现好像最后的状态转移方程和k并没有关系了,那么我们就干脆去掉k的那次循环

所以我们对核心代码进行了优化:

for(int i = 1 ; i <=n ;i++)
for(int j = 0 ; j <=m ;j++)
{
    f[i][j] = f[i-1][j];//状态一,即不取第i个物品
    if(j-v[i]>=0)//判断是否可以加入第i个物品
        f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);//状态二
}

完整代码如下:

#include<iostream>
using namespace std;
const int N=1010;
int f[N][N];
int n,m;
int v[N],w[N];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=m;j++)
        {
            f[i][j]=f[i-1][j];
            if(j>=v[i])
            {
                f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
            }
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}

我们来比较一个完全背包的核心代码和01背包核心代码的区别:

//01背包问题核心优化后代码
for(int i=1;i<=n;i++)
{
	for(int j=m;j>=v[i];j--)
	{	f[i][j]=f[i-1][j];
		if(j>=v[i])
		{
			f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
		}
	}
}
//完全背包问题核心优化后代码
for(int i = 1 ; i <=n ;i++)
for(int j = 0 ; j <=m ;j++)
{
    f[i][j] = f[i-1][j];//状态一,即不取第i个物品
    if(j-v[i]>=0)//判断是否可以加入第i个物品
        f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);//状态二
}

我们发现其实本质也就是一句不同:注意i的下标

在这里插入图片描述

我们这个i的下标是根据两个不同的背包问题的状态转移方程得出来的,我们01背包问题因为要使用第i-1层的数据,所以我们枚举j的时候只能从后往前枚举,这样做是因为j-v[i]小于j,那么f[j-v[i]]的数据就会被改,那么我们使用的数据其实就是第i层的数据了,不满足状态转移方程,所以我们要从后往前枚举,但是完全背包问题使用的就是第i层的数据,所以不存在从前往后枚举就会在使用前数据就发生意外改变的这种情况,所以就在这个地方这两个核心算法略有差别。

2.4思路三(优化j的初始条件)

这个和01背包问题的优化方法是一样的,就不多赘述了。

核心代码如下:

for(int i = 1 ; i<=n ;i++)
    for(int j = v[i] ; j<=m ;j++)//注意了,这里的j是从小到大枚举,和01背包不一样
    {
            f[j] = max(f[j],f[j-v[i]]+w[i]);
    }

完整代码如下:

#include<iostream>
using namespace std;
const int N = 1010;
int f[N];
int v[N],w[N];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i = 1 ; i <= n ;i ++)
    {
        cin>>v[i]>>w[i];
    }

    for(int i = 1 ; i<=n ;i++)
    for(int j = v[i] ; j<=m ;j++)
    {
            f[j] = max(f[j],f[j-v[i]]+w[i]);
    }
    cout<<f[m]<<endl;
}

总结

本篇博客开始进入动态规划,这次包括01背包问题和完全背包问题,分析了这两个动态规划算法的状态转移方程,从朴素算法开始入手对算法代码一步步进行优化,希望可以帮助到大家~

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

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

相关文章

求职-进度

2-23 投递 恒生校招 C https://campus.hundsun.com/personal/deliveryRecord 投递 合合信息 大数据开发工程师 https://intsig.zhiye.com/personal/deliveryRecord 投递 尚游网络 游戏服务器开发工程师 https://app.mokahr.com/campus_apply/shangyou/36582?recommendCodeDS…

项目管理中,哪些信息差是不应该存在的呢?

在项目管理中&#xff0c;如果存在信息差&#xff0c;那么就会存在了巨大的问题&#xff0c;从而导致项目的失败。 项目管理中哪些信息差是不应该存在的呢&#xff1f; 1、项目背景 项目经理接手项目&#xff0c;首先要了解清楚项目背景&#xff0c;避免在项目过程中对自己…

计算句子向量相似度:SentenceBert和SimCSE

SentenceBert Sentence-BERT: 如何通过对比学习得到更好的句子向量表示 - 哔哩哔哩 (bilibili.com) (229条消息) Sentence-BERT详解_数学家是我理想的博客-CSDN博客_sentence-bert 动机&#xff1a; 直接把2个句子串联起来输入Bert做分类&#xff08;即Cross-Encoder方式&…

Blazor入门100天 : 身份验证和授权 (6) - 使用 FreeSql orm 管理ids数据

目录 建立默认带身份验证 Blazor 程序角色/组件/特性/过程逻辑DB 改 Sqlite将自定义字段添加到用户表脚手架拉取IDS文件,本地化资源freesql 生成实体类,freesql 管理ids数据表初始化 Roles,freesql 外键 > 导航属性完善 freesql 和 bb 特性 本节源码 https://github.com/…

Maven基础-又简单又详细

如果文章对你有帮助欢迎【关注❤️❤️❤️点赞&#x1f44d;&#x1f44d;&#x1f44d;收藏⭐⭐⭐】一键三连&#xff01;一起努力&#xff01; 一、Maven简介 1、maven是什么 Maven的本质是一个项目管理工具&#xff0c;将项目开发和管理过程抽象成一个项目对象模型&#x…

JavaTCP通信程序

3 TCP通信程序 3.1 TCP通信原理 TCP通信协议是一种可靠的网络协议&#xff0c; 它在通信的两端名建立一个Socke对象&#xff0c; 从而在通信的两端形成网络虚拟链路一旦建立了 虚拟的网络链路&#xff0c;两端的程序就可以通过虚拟链路进行通信Java对基于TCP协议的的网络提供…

python3.11.2安装 + pycharm安装

下载 &#xff1a;https://www.python.org/ 2.双击下载的软件&#xff1a; 3.进入安装界面 下一步&#xff0c;点击 是 上一步点击后就看到如下&#xff1a; 安装成功了&#xff0c;接下来检测一下&#xff1a;cmd 安装pycharm PyCharm是一种Python IDE&#xff08;Integr…

office三件套与mathtype的安装和导入word

0. 前言 网上大部分说的不够具体&#xff0c;说的比较具体的就是下面这篇文章&#xff0c;但关键他路径还是错的。 MathType如何导入word 可能因为他是32位系统&#xff0c;所以office中某些路径和设置不一样&#xff0c;下文中一一指出。 mathtype导入word0. 前言1. 安装1.…

springboot整合springdata jpa全能书

一&#xff1a;spring data jpa介绍 spring data:其实spring data就是spring提供了一个操作数据的框架。而spirng data jpa只是spring data框架下的一个基于jpa标准操作数据的模块。 spring data jpa&#xff1a;基于jpa的标准对数据进行操作。简化操作持久层的代码。只需要编…

GEE学习笔记 五十二:Google Earth Studio初体验

Google Earth Studio出来一段时间了&#xff0c;自己也体验了一番。这里做一个简单的体验总结&#xff0c;为那些还没有体验过的小伙伴展示一下Google Earth Sutdio究竟长什么样子&#xff0c;能做什么&#xff1f; 注&#xff1a;这篇文章营养价值不大&#xff0c;纯粹是展示…

京东测开岗3+1面经+经验分享,拿到offer,月薪34k....

现在&#xff0c;招聘黄金时间已经来临&#xff0c;在网上看了很多大佬的面经&#xff0c;也加了很多交流群&#xff0c;受到了很多朋友的提点&#xff0c;今天终于轮到我来分享面经啦&#xff0c;之前面试了几家公司&#xff0c;最后拿到了京东测试岗的 offer&#xff0c;这里…

【机器学习、深度学习】损失函数

1.什么是损失函数 ​ 损失函数&#xff08;Loss Function&#xff09;又叫做误差函数&#xff0c;用来衡量算法拟合数据的好坏程度&#xff0c;评价模型的预测值与真实值的不一致程度&#xff0c;是一个非负实值函数&#xff0c;通常使用L(Y, f(x))​来表示&#xff0…

canvas初学1

前端数据可视化方案&#xff1a; 一、canvas绘制直线 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewpor…

CentOS 8利用Apache安装部署文件服务器

1&#xff1a;部署的目的是做一个类似下面开源镜像网站&#xff0c;把一些软件或者资料上传到服务器上面&#xff0c;减少用户在互联网上下载资料&#xff0c;提高效率&#xff0c;减少病毒。 2&#xff1a;使用下面的命令配置本机的IP地址主机名等信息。后期使用IP地址进行访问…

任意网络环境实现外网访问分销ERP

随着企业业务的不断扩展&#xff0c;经营网点遍布全国不同的区域&#xff0c;传统的管理手段存在诸多问题&#xff0c;无法实时监控各地分公司、办事处及营业网点的经营状况&#xff1b;订货、销售、库存等数据和信息反馈不及时&#xff0c;商品积压、缺货情况经常出现&#xf…

软件项目管理知识回顾---软件项目进度管理

软件项目进度管理 4.进度管理 4.1进度管理 1.概念&#xff1a;按时保质的完成任务 2.目的&#xff1a;按时完成任务&#xff0c;合理分配资源&#xff0c;发挥最佳的工作效率 3.活动&#xff1a;工作包分解出的进度活动 4.内容&#xff1a;项目进度计划的指定和项目进度计划的执…

一篇了解分布式id生成方案

系统唯一ID是我们在设计一个系统的时候常常会遇见的问题&#xff0c;也常常为这个问题而纠结。生成ID的方法有很多&#xff0c;适应不同的场景、需求以及性能要求。所以有些比较复杂的系统会有多个ID生成的策略。下面就介绍一些常见的ID生成策略。 1.数据库自增长序列或字段 …

BabylonJS之放烟花

BabylonJS烟花效果视频一&#xff1a; 技术调研 1. 方案一&#xff1a;ParticleSystem 用ParticleSystem来实现每一束的烟花效果&#xff0c;如果浏览器支持WebGL2功能&#xff0c;使用GPUParticleSystem性能会有极大的提升。 优点&#xff1a; 烟花效果易实现且效果好。 缺点…

什么是品牌营销?学会正确推广您的业务

什么是品牌营销&#xff1f; 品牌营销涉及长期战略规划&#xff0c;以推广整个品牌&#xff0c;而不是营销单个产品或服务。它分享了一个引人入胜的故事&#xff0c;以在潜在客户中产生品牌知名度并建立声誉。 面向消费者的品牌使用品牌智能软件来了解人们对其品牌的看法&#…

磨金石教育摄影技能干货分享|极简艺术与人文摄影相结合(一)

柏林街头&#xff08;德国&#xff09;照片中无论是景物元素还是色彩元素都很少&#xff0c;主体人物与道路外加一个箱子。极简艺术照片的减法做到了。一名女子端坐在路边&#xff0c;白色的衣服一尘不染&#xff0c;手持镜子补妆。虽然时间场地比较的随意&#xff0c;但是依然…