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

这篇具有很好参考价值的文章主要介绍了算法修炼之筑基篇——筑基一层中期(解决01背包,完全背包,多重背包)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

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

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

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

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

目录

✨详解文字版(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

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

🍓解法一:二维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]);	
    }
 } 

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

✨完全背包问题(经典)

🍓小明的背包2

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

🍓一维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背包,完全背包,多重背包)

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

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

算法修炼之筑基篇——筑基一层中期(解决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

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

#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])文章来源地址https://www.toymoban.com/news/detail-478089.html

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

到了这里,关于算法修炼之筑基篇——筑基一层中期(解决01背包,完全背包,多重背包)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【蓝桥杯-筑基篇】搜索

    🍓系列专栏:蓝桥杯 🍉个人主页:个人主页 目录 递归树 1.递归构建二进制串  2.全排列的 DFS 解法 3.全排列的 BFS 解法 4.数的划分法 5.图书推荐 递归树 递归树是一种用于分析递归算法时间复杂度的工具。它可以将递归算法的执行过程可视化,从而更好地理解算法的时间复杂度

    2024年01月16日
    浏览(71)
  • 【蓝桥杯-筑基篇】贪心

    🍓系列专栏:蓝桥杯 🍉个人主页:个人主页 目录 1.找零问题 ①暴力枚举 ②贪心 2.人性总是贪婪的 3.堆果子 4.图书推荐 有币种 1 、 2 、 4 、 5 、 10 若干张,找零 n 元,输出找零方案。 ①暴力枚举 这是一个找零问题,我们需要找到一种方案,使得用给定的硬币找零时,所需的

    2024年01月18日
    浏览(31)
  • 【蓝桥杯-筑基篇】动态规划

    🍓系列专栏:蓝桥杯 🍉个人主页:个人主页 目录 1.最大连续子段和 2.LCS 最大公共子序列 3.LIS 最长上升子序列 4.数塔 5.最大子矩阵和 6.背包问题 ①01背包问题 ②完全背包 这段代码是一个求最大子数组和的算法,使用的是动态规划的思想。下面是代码的解释: 首先定义了一个

    2023年04月24日
    浏览(62)
  • 百日筑基篇——python爬虫学习(一)

    百日筑基篇——python爬虫学习(一) 随着学习的深入,有关从各种不同的数据库中以及互联网上的海量信息,如何有选择性的爬取我们所需的数据以方便我们的数据分析工作,爬虫的学习是必要的。 Python爬虫是指使用Python编程语言编写的程序,通过模拟浏览器行为从网页中

    2024年02月13日
    浏览(38)
  • MySQL筑基篇之增删改查

    ✅作者简介:C/C++领域新星创作者,为C++和java奋斗中 ✨个人社区:微凉秋意社区 🔥系列专栏:MySql一点通 📃推荐一款模拟面试、刷题神器👉注册免费刷题 🔥前言 本文将承接前两篇MySQL专栏的博文,讲解数据库的 增删改查 操作,这里的查询确切的说应该是初级的查询,不

    2024年02月12日
    浏览(43)
  • C++修炼之筑基期第三层——拷贝构造函数

    🌸作者简介: 花想云 ,在读本科生一枚,致力于 C/C++、Linux 学习。 🌸 本文收录于 C++系列 ,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,专为大学生打造全套 C++ 学习教程,持续更新! 🌸 相关专栏推荐: C语言初阶系列 、 C语言进阶系列 、 数据结构与算法 本章主要

    2023年04月09日
    浏览(27)
  • C++修炼之筑基期第四层 ——透过日期类看运算符重载 | 赋值运算符重载 | 取地址操作符重载

    🌸作者简介: 花想云 ,在读本科生一枚,致力于 C/C++、Linux 学习。 🌸 本文收录于 C++系列 ,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,专为大学生打造全套 C++ 学习教程,持续更新! 🌸 相关专栏推荐: C语言初阶系列 、 C语言进阶系列 、 数据结构与算法 本章主要

    2023年04月09日
    浏览(75)
  • 音频筑基:算法时延分析

    音频算法中,经常遇到时延分析的问题,刚开始接触大多都比较迷惑,这里将自己对时延的学习思考梳理总结于此。 音频领域中,时延(delay/latency)主要指声音从源端发出,经链路传输,再到对端接收到声音,所经过的总时间延迟。一般人耳无法感知的蓝牙段链路时延是25-30

    2024年01月17日
    浏览(28)
  • 算法修炼之练气篇——练气七层

    博主:命运之光 专栏:算法修炼之练气篇 前言:每天练习五道题,炼气篇大概会练习200道题左右,题目有C语言网上的题,也有洛谷上面的题,题目简单适合新手入门。(代码都是命运之光自己写的,练完这200多道题就考了今年第十四届的B组蓝桥杯C/C++获得了省一,后面还会

    2024年02月05日
    浏览(32)
  • 算法修炼之练气篇——练气十层

    博主:命运之光 专栏:算法修炼之练气篇 前言:每天练习五道题,炼气篇大概会练习200道题左右,题目有C语言网上的题,也有洛谷上面的题,题目简单适合新手入门。(代码都是命运之光自己写的,练完这200多道题就考了今年第十四届的B组蓝桥杯C/C++获得了省一,后面还会

    2024年02月05日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包