算法修炼之筑基篇——筑基一层中期(解决01背包,完全背包,多重背包)

news2024/12/20 20:12:00

博主:命运之光​​​​​​

🦄专栏:算法修炼之练气篇​​​​​

🍓专栏:算法修炼之筑基篇

博主的其他文章:点击进入博主的主页​​​​​​

前言:学习了算法修炼之练气篇想必各位蒟蒻们的基础已经非常的扎实了,下来我们进阶到算法修炼之筑基篇的学习。筑基期和练气期难度可谓是天差地别,懂得都懂,题目难度相比起练气期的题目难度提升很多,所以要是各位蒟蒻小伙伴们看不懂筑基期的题目可以在练气期多积累积累,练气期的题目也会不断更新,大家一定要把基础打牢固了再来看筑基期的题目哈,这样子也可以提高大家的学习效率,一举两得,加油(●'◡'●)🎉🎉

目录

✨详解文字版(01背包,完全背包,多重背包)

🍓01背包问题

 🍓完全背包问题

🍓多重背包问题

✨01背包问题(经典)

🍓小明的背包1

🍓解法一:二维dp数组

🍓解法二:一维dp数组

✨完全背包问题(经典)

🍓小明的背包2

🍓一维dp数组

🍓一维dp数组关键步骤(记忆)

🍓01背包和完全背包两个对比(重要)

😭总结就一个公式(超级无敌重要)

🍓🍓01背包总结

🍓🍓完全背包总结

✨多重背包问题(经典)

🍓小明的背包3

🍓重要步骤


✨详解文字版(01背包,完全背包,多重背包)

光看文字我感觉,很难理解背包问题,关键还是要看看底下的经典例题,看完差不多就可以了,问题不好理解,大家加油哈(●'◡'●)

背包问题的理解和解法。这三种问题分别是:

  • 01背包问题:每种物品只能选择一次,求最大价值。
  • 完全背包问题:每种物品可以选择无限次,求最大价值。
  • 多重背包问题:每种物品有一个选择上限,求最大价值。

这三种问题都可以用动态规划的思想来解决,关键是找到状态转移方程。下面我就分别介绍一下这三种问题的思路和代码实现。(看不懂的话可以直接跳到例题,看例题我感觉就能直接理解,不用文字这么的啰嗦哈哈啊哈🤭)

🍓01背包问题

01背包问题是所有背包问题的基础,之后的问题都可以在此基础之上变化,所以一定要理解清楚。尤其是对待不同问题,找出状态转移方程是解题的关键。

假设有N件物品和一个容量为V的背包。第i件物品的体积是v[i],价值是w[i]。我们用f[i][j]表示前i件物品恰好放入一个容量为j的背包中的最大价值。那么我们可以得到如下的状态转移方程:

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

这个方程的意思是,对于第i件物品,我们有两种选择:放或者不放。如果不放,那么前i件物品的最大价值就等于前i-1件物品的最大价值;如果放,那么前i件物品的最大价值就等于前i-1件物品在剩余空间j-v[i]中的最大价值加上第i件物品的价值。我们取这两种情况中较大的一个作为f[i][j]的值。

根据这个方程,我们可以用二维数组来存储f[i][j]的值,并从小到大遍历所有可能的状态。最终答案就是f[N][V]。

🍓下面是用C++实现的代码:

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1001; // 物品数量和背包容量的上限
int f[N][N]; // 存储状态转移方程的结果
int v[N]; // 存储每件物品的体积
int w[N]; // 存储每件物品的价值

int main() {
int n, V; // 物品数量和背包容量
cin >> n >> V;
for (int i = 1; i <= n; i++) {
cin >> v[i] >> w[i]; // 输入每件物品的体积和价值
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= V; j++) {
f[i][j] = f[i-1][j]; // 不放第i件物品
if (j >= v[i]) { // 如果能放得下第i件物品
f[i][j] = max(f[i][j], f[i-1][j-v[i]] + w[i]); // 取放和不放中较大的一个
}
}
}
cout << f[n][V] << endl; // 输出最大价值
return 0;
}


 🍓完全背包问题

完全背包问题与01背包问题非常相似,只是每种物品可以选择无限次而已。这样一来,我们的状态转移方程就有所变化:

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

这个方程的意思是,对于第i件物品,我们有两种选择:放或者不放。如果不放,那么前i件物品的最大价值就等于前i-1件物品的最大价值;如果放,那么前i件物品的最大价值就等于当前物品在剩余空间j-v[i]中的最大价值加上第i件物品的价值。注意这里和01背包问题的区别,因为可以放多次,所以是f[i][j-v[i]]而不是f[i-1][j-v[i]]。

根据这个方程,我们仍然可以用二维数组来存储f[i][j]的值,并从小到大遍历所有可能的状态。最终答案仍然是f[N][V]。

🍓下面是用C++实现的代码:

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1001; // 物品数量和背包容量的上限
int f[N][N]; // 存储状态转移方程的结果
int v[N]; // 存储每件物品的体积
int w[N]; // 存储每件物品的价值

int main() {
int n, V; // 物品数量和背包容量
cin >> n >> V;
for (int i = 1; i <= n; i++) {
cin >> v[i] >> w[i]; // 输入每件物品的体积和价值
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= V; j++) {
f[i][j] = f[i-1][j]; // 不放第i件物品
if (j >= v[i]) { // 如果能放得下第i件物品
f[i][j] = max(f[i][j], f[i][j-v[i]] + w[i]); // 取放和不放中较大的一个
}
}
}
cout << f[n][V] << endl; // 输出最大价值
return 0;
}

🍓多重背包问题

多重背包问题的描述是这样的:有n种物品和一个容量为m的背包,每种物品有一定的重量w[i]和价值v[i],还有数量限制num[i],即每种物品最多只能放num[i]个。问如何选择放入背包的物品,使得背包内物品的总价值最大,且不超过背包的容量。🤔

这个问题看起来很复杂,但其实我们可以用一些技巧来简化它。首先,我们可以把每种物品看成是若干个01背包问题中的物品,即把第i种物品分成num[i]个单独的物品,每个物品的重量和价值都是w[i]和v[i]。这样我们就把多重背包问题转化成了一个01背包问题。😎

然后,我们可以用一个二维数组dp[i][j]来表示从前i个物品中选择若干个放入容量为j的背包时能获得的最大价值。我们可以用一个循环来遍历所有的物品,对于每个物品,我们又用一个循环来遍历所有可能的背包容量,然后根据放或不放这个物品来更新dp[i][j]的值。具体来说,如果不放这个物品,那么dp[i][j]就等于dp[i-1][j],即前i-1个物品放入容量为j的背包时能获得的最大价值;如果放这个物品,那么dp[i][j]就等于dp[i-1][j-w[i]]+v[i],即前i-1个物品放入容量为j-w[i]的背包时能获得的最大价值加上当前物品的价值。我们要在这两种情况中取较大的那个作为dp[i][j]的值。👍

最后,我们可以输出dp[n][m]作为最终答案,即从n种物品中选择若干个放入容量为m的背包时能获得的最大价值。这就是多重背包问题的解法。🎉

01背包问题(经典)

🍓小明的背包1

🍓解法一:二维dp数组

#include<bits/stdc++.h>
using namespace std;
int dp[1005][1005],w[1005],v[1005];
int main()
{
	//经典的01背包问题需要记忆 
	int n,m;
	int i,j;
	cin>>n>>m;
	for(i=1;i<=n;i++)
	{
		cin>>w[i]>>v[i];
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			if(j<w[i])
			{
				dp[i][j]=dp[i-1][j];//记忆	
			}
			else
			{
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);//记忆 
			}	
		}
	 } 	 
	cout<<dp[n][m];	
	return 0;
}

🍓解法二:一维dp数组

#include<bits/stdc++.h>
using namespace std;
int dp[1005],w[1005],v[1005];
int main()
{
	//经典的01背包问题需要记忆 
	int n,m;
	int i,j;
	cin>>n>>m;
	for(i=1;i<=n;i++)
	{
		cin>>w[i]>>v[i];
	}
	for(i=1;i<=n;i++)
	{
		for(j=m;j>=1;j--)//--j和j--不影响,01背包是逆序 
		{
			if(j>w[i])
			{
				dp[j]=max(dp[j-1],dp[j-w[i]]+v[i]);
			}	
		}
	 } 	 
	cout<<dp[m];	
	return 0;
}

🍓用这个dp[j]=max(dp[j],dp[j-w[i]]+v[i])

#include<bits/stdc++.h>
using namespace std;
int dp[1005],w[1005],v[1005];
int main()
{
	//经典的01背包问题需要记忆 
	int n,m;
	int i,j;
	cin>>n>>m;
	for(i=1;i<=n;i++)
	{
		cin>>w[i]>>v[i];
	}
	for(i=1;i<=n;i++)
	{
		for(j=m;j>=1;j--)//--j和j--不影响,01背包是逆序 
		{
      		if(j>=w[i])
				dp[j]=max(dp[j],dp[j-w[i]]+v[i]);	
		}
	 } 	 
	cout<<dp[m];	
	return 0;
}

下面是需要记忆知识点(01背包问题中的推到公式需要记忆)

🍓二维dp数组

	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			if(j<w[i])
			{
				dp[i][j]=dp[i-1][j];//记忆	
			}
			else
			{
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);//记忆 
			}	
		}
	 }

🍓一维dp数组(重要)

for(i=1;i<=n;i++)
{
    for(j=m;j>=1;j--)//--j和j--不影响,01背包是逆序 
    {
        if(j>=w[i])
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);	
    }
 } 

完全背包问题(经典)

🍓小明的背包2

🍓一维dp数组

#include<bits/stdc++.h>
using namespace std;
int dp[1005],w[1005],v[1005];
int main()
{
	//经典的完全背包问题需要记忆 
	int n,m;
	int i,j;
	cin>>n>>m;
	for(i=1;i<=n;i++)
	{
		cin>>w[i]>>v[i];
	}
	for(i=1;i<=n;i++)
	{
		for(j=w[i];j<=m;j++)
		{
			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
		}
	 } 	 
	cout<<dp[m];	
	return 0;
}

🍓一维dp数组关键步骤(记忆)

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

🍓01背包和完全背包两个对比(重要)

😭总结就一个公式(超级无敌重要)

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

其中01背包是逆向推到,完全背包是正向推到

🍓🍓01背包总结

for(i=1;i<=n;i++)
{
    for(j=m;j>=1;j--)//--j和j--不影响,01背包是逆序 
    {
        if(j>=w[i])
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);	
    }
 } 

🍓🍓完全背包总结

for(i=1;i<=n;i++)
{
    for(j=w[i];j<=m;j++)//重要点,j=w[i];j<=m;j++
    {
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    }
 } 

✨多重背包问题(经典)

理解了上面的01背包问题和多重背包问题就很好理解多重背包问题了

🍓小明的背包3

#include<bits/stdc++.h>
using namespace std;
int dp[205],w[205],vi[205],s[205];
int main()
{
	//经典的多重背包问题 
	int n,v;
	int i,j;
	cin>>n>>v;
	for(i=1;i<=n;i++)
	{
		cin>>w[i]>>vi[i]>>s[i];
	}
	
	for(i=1;i<=n;i++)
	{
		for(j=v;j>=1;j--)
		{
			for(int k=0;k<=s[i]&&j>=k*w[i];++k)
			{
				//从01背包的状态转移方程式,去增加i个物品拿k个循环 
				dp[j]=max(dp[j],dp[j-k*w[i]]+k*vi[i]);
			}
		}
	}
	cout<<dp[v]; 
	return 0;
}

🍓重要步骤

🍓就是在01背包的基础上加上K循环的约束条件dp[j]=max(dp[j],dp[j-k*w[i]]+k*vi[i])

for(i=1;i<=n;i++)
	{
		for(j=v;j>=1;j--)//01背包的基础上他这个也是逆向的
		{
			for(int k=0;k<=s[i]&&j>=k*w[i];++k)
			{
				//从01背包的状态转移方程式,去增加i个物品拿k个循环 
				dp[j]=max(dp[j],dp[j-k*w[i]]+k*vi[i]);
			}
		}
	}

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

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

相关文章

安全——网络安全协议的引入

TCP/IP安全缺陷 信息泄露 概述 网络中投递的报文往往包含账号、口令等敏感信息&#xff0c;若这些信息泄露则是灾难性的后果。其中嗅探是一种常见而隐蔽的网络攻击手段。 嗅探 概述 问题&#xff1a;在共享式网络架构下&#xff0c;所有的数据都是以广播方式进行发送&…

程序员大专毕业,月薪2w是什么体验?

在这个数据驱动的时代&#xff0c;大数据行业的发展前景也非常广阔&#xff0c;我相信我的未来会越来越光明 01 开始学习 是迈向前方的第一步 我是三月&#xff0c;一个来自小城市的大专毕业生。现在在杭州一家公司做大数据开发工程师&#xff0c;目前薪资是20k*13。 我本身…

运维小白必学篇之基础篇第十三集:网络概述中继实验

网络概述中继实验 实验作业&#xff08;主机名为自己的名字&#xff09;&#xff1a; 1、搭建中继环境&#xff0c;要求如下&#xff1a; 网络要求&#xff1a; 内网&#xff1a;192.168.50.50 网关&#xff1a;192.168.50.254 192.168.60.254 外网&#xff1a;192.168.60.60 主…

【论文阅读】An Object SLAM Framework for Association, Mapping, and High-Level Tasks

一、系统概述 这篇文章是一个十分完整的物体级SLAM框架&#xff0c;偏重于建图及高层应用&#xff0c;在前端的部分使用了ORBSLAM作为基础框架&#xff0c;用于提供点云以及相机的位姿&#xff0c;需要注意的是&#xff0c;这篇文章使用的是相机&#xff0c;虽然用的是点云这个…

DevOps该怎么做?

年初在家待了一段时间看了两本书收获还是挺多的. 这些年一直忙于项目, 经历了软件项目的每个阶段, 多多少少知道每个阶段是个什么, 会做哪些事情浮于表面, 没有深入去思考每个阶段背后的理论基础, 最佳实践和落地工具. 某天leader说你书看完了, 只有笔记没有总结, 你就写个总结…

小白必看!轻松理解和解决MySQL幻读问题!

大家好&#xff0c;我是小米&#xff01;今天我来给大家分享一下关于MySQL数据库中常见的一个问题——幻读&#xff0c;以及如何解决它。相信对于数据库开发和管理的小伙伴们来说&#xff0c;幻读是一个相对棘手的问题&#xff0c;但只要我们掌握了正确的解决方法&#xff0c;它…

网络故障管理

网络故障管理是以最快的方式查找、隔离和排除网络故障的过程。故障管理是网络管理的重要组成部分&#xff0c;它通过快速解决故障来最大限度地减少停机时间并防止设备故障&#xff0c;从而确保最佳的网络可用性并防止业务损失。 网络故障监控是故障管理的第一步&#xff0c;因…

Linux Shell脚本攻略

一、echo命令 1、在echo中转义换行符 默认情况下&#xff0c;echo会在输出文本的尾部追加一个换行符。可以使用选项-n来禁止这种行为。 echo同样接受双包含转义序列的双引号字符串作为参数。在使用转义序列时&#xff0c;需要使用echo -e "包含转义序列的字符串"这…

有哪些测试框架和工具推荐? - 易智编译EaseEditing

在软件测试领域&#xff0c;有许多测试框架和工具可供选择。以下是一些常见的测试框架和工具的推荐&#xff1a; Selenium: 一个用于自动化Web应用程序测试的流行框架。它支持多种编程语言&#xff0c;并提供丰富的功能和灵活性。 JUnit: 一个用于Java应用程序的单元测试框架…

MongoDB(学习笔记1.0)

最近在学非关系型数据库MongoDB&#xff0c;猛地用起来的真的没关系型数据库方便啊。 首先还是数据库的安装&#xff1a; 安装直接去官网安装即可&#xff0c;官网地址&#xff1a;MongoDB: The Developer Data Platform | MongoDB 当前也有免安装版的&#xff0c;这里就不再…

毕业三年,自学软件测试到就业,我用了4个月

我转行的经历 17年毕业&#xff0c;普通专科&#xff0c;通信专业。 当初选择这个专业是因为有一个校企合作&#xff0c;承诺学生毕业之后给学生安排就业&#xff0c;在学校里面混了三年之后&#xff0c;学校也是履行了当初安排就业的承诺&#xff0c;给我“发配”到了上海&a…

chatgpt赋能python:Python同一行输入

Python同一行输入 在Python编程中&#xff0c;你可能需要在同一行中输入多个命令或语句。这可以通过使用分号来实现。 在本文中&#xff0c;我们将介绍如何在Python中使用同一行输入&#xff0c;并探讨其优缺点。 使用分号实现同一行输入 在Python中&#xff0c;分号&#x…

地震勘探基础(九)之地震速度分析

速度分析 在地震资料数字处理中&#xff0c;速度分析是动校正和水平叠加和地震偏移的基础。 在水平界面情况下&#xff0c;共中心点时距曲线方程是一条双曲线。在共中心点时距曲线中&#xff0c;炮检距 x x x 和时间 t 0 t_0 t0​ 都是已知的&#xff0c;只有速度 v v v 是…

30天从入门到精通TensorFlow1.x 第五天,跨计算设备执行计算图-cpu

一、接前一天 前天学习了&#xff0c;数据流图&#xff0c;今天尝试在不同设备上&#xff08;cpu或者gpu&#xff09;来执行计算图。 本次使用cpu来执行&#xff0c;但是不涉及gpu。gpu放在后面学习&#xff0c;这里比较重要。 二、示例 1. 先看看自己的设备 from tensorfl…

My Note of Diffusion Models

Diffusion Models Links: https://theaisummer.com/diffusion-models/ Markovian Hierachical VAE rvs: data: x 0 x_{0} x0​,representation: x T x_{T} xT​ ( p ( x 0 , x 1 , ⋯ , x T ) , q ( x 1 , ⋯ , x T ∣ x 0 ) ) (p(x_0,x_1,\cdots,x_T),q(x_1,\cdots,x_{T…

AcWing 回转游戏 dfs IDA* 剪枝 统一操作 java

&#x1f351; 算法题解专栏 &#x1f351; 回转游戏 如下图所示&#xff0c;有一个 # 形的棋盘&#xff0c;上面有 1 , 2 , 3 1,2,3 1,2,3 三种数字各 8 8 8 个。 给定 8 8 8 种操作&#xff0c;分别为图中的 A s i m H A \\sim H AsimH。 这些操作会按照图中字母和箭头…

ChatGPT会取代低代码开发平台吗?

编程作为一种高端技能&#xff0c;向来是高收入高科技的代名词。近期&#xff0c;伴随着ChatGPT在全球的爆火&#xff0c;过去通过窗口“拖拉拽”的所见即所得方式的低代码开发模式&#xff0c;在更加智能和更低成本的AI搅局之下&#xff0c;又面临了更深层次的影响。 低代码平…

MySQL redo log、undo log、binlog

MySQL是一个广泛使用的关系型数据库管理系统&#xff0c;它通过一系列的日志来保证数据的一致性和持久性。在MySQL中&#xff0c;有三个重要的日志组件&#xff0c;它们分别是redo log&#xff08;重做日志&#xff09;、undo log&#xff08;回滚日志&#xff09;和binlog&…

MyBatis深入学习总结

MyBatis总结 MyBatis入门操作 简介 原始jdbc操作&#xff08;查询数据&#xff09; 原始jdbc操作&#xff08;插入数据&#xff09; 原始jdbc操作的分析 原始jdbbc开发存在的问题如下&#xff1a; 数据库连接创建、释放频繁造成系统资源的浪费从而影响系统性能sql语句在代…

深度学习基础知识-tf.keras实例:衣物图像多分类分类器

参考书籍&#xff1a;《Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow, 2nd Edition (Aurelien Geron [Gron, Aurlien])》 本次使用的数据集是tf.keras.datasets.fashion_mnist&#xff0c;里面包含6w张图&#xff0c;涵盖10个分类。 import tensorflo…