背包问题(01背包、完全背包、多重背包)详解(超详细!!!),及题目代码和题意,包含6个例题。

news2024/9/25 1:21:59

第一题:01背包问题

01背包问题

时间限制:1秒        内存限制:128M

题目描述

一个旅行者有一个最多能装 M 公斤的背包,现在有 n 件物品,它们的重量分别是 W1,W2,...,Wn ,它们的价值分别为 C1 , C2 ,..., Cn ,求旅行者能获得最大总价值。

输入描述

第一行:两个整数,M (背包容量,M≤200 )和 N (物品数量, N≤30 );
第 2..N+1 行:每行二个整数 Wi,Ci ,表示每个物品的重量和价值。

输出描述

仅一行,一个数,表示最大总价值。

样例

输入

10 4
2 1
3 3
4 5
7 9

输出

12

重要信息筛选

最多能装 M 公斤的背包,现在有 n 件物品,它们的重量分别是 W1,W2,...,Wn ,它们的价值分别为 C1 , C2 ,..., Cn ,求最大总价值

思路:

对于每个物品有两个选择,放入或者不放,有 n 个物品,所以要做出 n 个选择,可以视为 n个状态阶段。
用 f[n][m]表示有 n 个物品时,放入容量为 m 的背包所能获得的最大价值。样例要求的就是 f[4][10]。
包容量为 10,考虑第 4 个物品(重量为 2,价值为 1),分两种情况:
1)放入第 4 个物品
对应的背包价值为前 3 个物品放在容量为(10-2)的包里的最大价值+第 4 个物品的价值。
f[4][10]=f[3][10-2]+1=f[3][8]+1
f[3][8]代表什么含义呢?
 -有前 3 个物品时,放入容量为 8 的背包所能获得的最大价值
 -考虑第 3 个物品,同样分为两种情况
a.f[3][8]=f[2][4]+5
b.f[3][8]=f[2][8]
2)不放入第 4 个物品
对应的背包价值和前 3 个物品放在容量为 10 的包里的价值一样。 f[4][10]=f[3][10]
1 和 2 两种情况哪个的背包价值更大,f[4][10]就是哪个值。


用 f[i][j]表示背包中有 i 个物品,重量为 j 时的价值情况,如下图所示:


以 f[2][8]为例, f[2][8]=max(f[1][8-3]+3,f[1][8])
 = max(f[1][5]+3,f[1][8])


求 f[2][8]的值时,只需要知道 f[1][8]左侧部分的数据即可。

其实把它优化成一维的,也是可行的,因为不用i-1,直接每次求最大值。此时状态转移方程变成这样:

此时,代码主体框架已经完成,完成输入输出即可

AC代码:

#include<bits/stdc++.h>
using namespace std;
int dp[10000005],w[10005],c[10005];//定义 
int main(){
    int n,m,cnt=0;
    scanf("%d%d",&m,&n);//输入最大容量和数量 
    for(int i=1; i<=n; i++){
    	cin>>w[i]>>c[i];//输入重量和 
	}
	for(int i=1;i<=n;i++){//枚举所有物品
	    for(int j=m;j>=w[i];j--){//枚举从最大容量到当前物品重量
	        dp[j]=max(dp[j],dp[j-w[i]]+c[i]);//dp[当前容量]=max(dp[当前容量],dp[当前容量-当前物品重量]+当前物品价值);
	    }
	}
    printf("%d",dp[m]);//输出 
    return 0;
}

第二题:采药

采药

时间限制:1秒        内存限制:128M

题目描述

辰辰是个很有潜能、天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。

如果你是辰辰,你能完成这个任务吗?

输入描述

输入的第一行有两个整数T(1≤T≤1000)和M(1≤M≤100),T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出描述

输出只包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

样例

输入

70 3
71 100
69 1
1 2

输出

3

思路:

转化为T为背包容量M为物品数量采药时间看成重量采药价值看成价值,再套用01背包完成此问题

 对于每个物品有两个选择,放入或者不放,有 n 个物品,所以要做出 n 个选择,可以视为 n个状态阶段。
用 f[n][m]表示有 n 个物品时,放入容量为 m 的背包所能获得的最大价值。样例要求的就是 f[4][10]。
包容量为 10,考虑第 4 个物品(重量为 2,价值为 1),分两种情况:
1)放入第 4 个物品
对应的背包价值为前 3 个物品放在容量为(10-2)的包里的最大价值+第 4 个物品的价值。
f[4][10]=f[3][10-2]+1=f[3][8]+1
f[3][8]代表什么含义呢?
 -有前 3 个物品时,放入容量为 8 的背包所能获得的最大价值
 -考虑第 3 个物品,同样分为两种情况
a.f[3][8]=f[2][4]+5
b.f[3][8]=f[2][8]
2)不放入第 4 个物品
对应的背包价值和前 3 个物品放在容量为 10 的包里的价值一样。 f[4][10]=f[3][10]
1 和 2 两种情况哪个的背包价值更大,f[4][10]就是哪个值。


用 f[i][j]表示背包中有 i 个物品,重量为 j 时的价值情况,如下图所示:


以 f[2][8]为例, f[2][8]=max(f[1][8-3]+3,f[1][8])
 = max(f[1][5]+3,f[1][8])


求 f[2][8]的值时,只需要知道 f[1][8]左侧部分的数据即可。

其实把它优化成一维的,也是可行的,因为不用i-1,直接每次求最大值。此时状态转移方程变成这样:

此时,代码主体框架已经完成,完成输入输出即可

AC代码:

#include<bits/stdc++.h>
using namespace std;
int dp[10000005],w[10005],c[10005];//定义 
int main(){
    int n,m,cnt=0;
    scanf("%d%d",&m,&n);//输入最大容量和数量 
    for(int i=1; i<=n; i++){
    	cin>>w[i]>>c[i];//输入重量和 
	}
	for(int i=1;i<=n;i++){//枚举所有物品
	    for(int j=m;j>=w[i];j--){//枚举从最大容量到当前物品重量
	        dp[j]=max(dp[j],dp[j-w[i]]+c[i]);//dp[当前容量]=max(dp[当前容量],dp[当前容量-当前物品重量]+当前物品价值);
	    }
	}
    printf("%d",dp[m]);//输出 
    return 0;
}

第三题:数字组合

数字组合

时间限制:1秒        内存限制:128M

题目描述

在N个数中找出其和为M的若干个数。先读入正整数N(1< N< 100)和M(1< M< 10000),再读入N个正数(可以有相同的数字,每个数字均在1000以内),在这N个数中找出若干个数,使它们的和是M,把满足条件的数字组合都找出来以统计组合的个数,输出组合的个数(不考虑组合是否相同)。要求你的程序运行时间不超过1秒。

输入描述

第一行是两个数字,表示N和M。 第二行起是N个数。

输出描述

就一个数字,表示和为M的组合的个数。

样例

输入

4 4
1 1 2 2

输出

3

思路:

这是典型的 0/1 背包模型,n 个正整数就是 n 个物品,t 就是背包的容积。
在外层循环到 i 时(表示从前 i 个数中选),设 f[j]表示“和为 j”有多少种方案。在具体实现中,只需要把上面代码中求 max 的函数改为求和即可。

这边为大家奉上代码

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,m,a[10005],f[10005];
	cin>>n>>m;
	for(int i=1; i<=n; i++) cin>>a[i];
	f[0]=1;
	for(int i=1; i<=n; i++){
		for(int j=m; j>=a[i]; --j){
			f[j]+=f[j-a[i]];
		}
	}
	cout<<f[m]<<endl;
    return 0;
}

第四题:完全背包问题

完全背包问题

时间限制:1秒        内存限制:128M

题目描述

设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。

输入描述

第一行:两个整数,M(背包容量,M≤200)和N(物品数量,N≤30); 

第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。

输出描述

仅一行,一个数,表示最大总价值。

样例

输入

10 4
2 1
3 3
4 5
7 9

输出

max=12

思路:

状态为 f[x],表示包容量为 x 时获得的最大价值
放入的最后一个物品可能是重量小于 x 的任何一个,选最大的那个
f[12],包容量为 12 时获得的最大价值
只考虑最后一个物品,分四种情况
1)最后一个是物品①(重量为 2,价值为 1)
f[12]=f[12-2]+1=f[10]+1
2)最后一个是物品②(重量为 3,价值为 3)
f[12]=f[12-3]+3=f[9]+3
3)最后一个是物品③(重量为 4,价值为 5)
f[12]=f[12-4]+5=f[8]+5
4)最后一个是物品④(重量为 7,价值为 9)
f[12]=f[12-7]+9=f[5]+9
找四种情况里最大的那个
f[5],包容量为 5 时获得的最大价值
只考虑最后一个物品,分三种情况
1)最后一个是物品①(重量为 2,价值为 1)
f[5]=f[5-2]+1=f[3]+1
2)最后一个是物品②(重量为 3,价值为 3)
f[5]=f[5-3]+3=f[2]+3
3)最后一个是物品③(重量为 4,价值为 5)
f[5]=f[5-4]+5=f[1]+5
4)最后一个可能是物品④(重量为 7,价值为 9)吗?

所以,根据思路,即可写出代码:

#include<bits/stdc++.h>
using namespace std;
int f[10000005],w[10005],c[10005];
int main(){
    int n,m,cnt=0;
    scanf("%d%d",&m,&n);
    for(int i=1; i<=n; i++){
    	cin>>w[i]>>c[i];
	}
	for(int i=1;i<=n;i++){
	    for(int j=w[i];j<=m;j++){//01背包是从m到w[i],完全背包是w[i]到m
	        f[j]=max(f[j],f[j-w[i]]+c[i]);
	    }
	}
    printf("max=%d",f[m]);
    return 0;
}

第五题:多重背包

多重背包

时间限制:1秒        内存限制:128M

题目描述

现有N种(N<=10)魔法石和一个容量为V(0<V<200)的背包。第i种魔法石最多有n[i]件可用,每个占用的空间是c[i],价值是w[i]。全部物品总数不超过50.求解将哪些魔法石装入背包可使这些物品的容量总和不超过背包容量,且价值总和最大

输入描述

第一行为两个数字,即V和N。以下N行为每种物品的空间,价值和数量

输出描述

最大价值总和

样例

输入

8 2
2 100 4
4 100 2

输出

400

对于每个物品有 ?个选择
用 f[n][m]表示有 n 个物品时,放入容量为 m 的背包所能获得的最大价值。样例要求的就是 f[2][8]。
包容量为 8,考虑物品②(空间为 4,价值为 100,总量为 2),分 3 种情况1)放入 0 个物品②
f[2][8]=f[1][8]
2)放入 1 个物品②
f[2][8]=f[1][8-4]+100=f[1][4]+100
2)放入 2 个物品②
f[2][8]=f[1][8-4*2]+100*2=f[1][0]+200


3 种情况哪个的背包价值更大,f[2][8]就是哪个值。

也可以用一维数组进行优化
程序:

#include<bits/stdc++.h>
using namespace std;
int f[40005];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    int c[2005],w[2005],s[2005];
    for(int i=1; i<=n; i++){
        scanf("%d%d%d",w+i,c+i,s+i);
    }
    for(int i=1;i<=n;i++){
	    for(int k=1;k<=s[i];k++){   
	         for(int j=m;j>=w[i];j--){
	              f[j]=max(f[j],f[j-w[i]]+c[i]);
	         }
	    }
	} 
    printf("%d",f[m]);
    return 0;
}

第六题:买书

买书

时间限制:1秒        内存限制:128M

题目描述

小明手里有n元钱全部用来买书,书的价格为10元,20元,50元,100元。 

问小明有多少种买书方案?(每种书可购买多本)

输入描述

一个整数 n,代表总共钱数。(0 <= n <= 1000)

输出描述

一个整数,代表选择方案种数

样例

输入

20

输出

2

题目分析:


现在有四种类型的书,可以类比成四种物品,重量就是书的价格,可以用完全背包的方法来
求解,但是本题目不是求最大价值,而是求方案数。完全背包问题求解方案数把 max 修改成 sum 就可以了
f[i][j]表示前 i 件物品放到背包容量为 j 的背包的方案数
状态转移方程:
f[i][j] += f[i-1][j-w[i]]

初始化为:f[0][0] = 1
也可以用一维优化
f[i]表示放到背包容量为 i 的背包里面总共有多少种方案
状态转移方程:
f[j] += f[j - a[i]];

代码:

#include<bits/stdc++.h>
using namespace std;
int a[]={0,10,20,50,100};
int f[20000005];
int main(){
	int n;
	cin>>n;
	f[0]=1;
	for(int i=1; i<=4; i++){
		for(int j=a[i]; j<=n; ++j){
			f[j]+=f[j-a[i]];
		}
	}
	cout<<f[n]<<endl;
    return 0;
}

总结:背包问题真难啊

往期回顾:

可达鸭二月月赛——入门赛第四场T1题解

可达鸭二月月赛——入门赛第四场T2题解

可达鸭二月月赛——入门赛第四场T3题解

可达鸭二月月赛——入门赛第四场T4题解

可达鸭二月月赛——入门赛第四场(周三)题解

点个赞吧,求求了,制作不易。

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

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

相关文章

Netty的常用组件及线程模型设计(一)

Netty常用组件 Bootstrap Bootstrap是Netty框架的启动类和主入口类&#xff0c;发呢为客户端类Bootstrap和服务器类ServerBootstrap两种 Channel Channel是JavaNIO的一个基本构造&#xff0c;它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一…

电缆线的阻抗50Ω,真正含义是什么?

当我们提到电缆线的阻抗时&#xff0c;它到底是什么意思&#xff1f;RG58电缆通常指的是50Ω的电缆线。它的真正含义是什么&#xff1f;假如取一段3英尺(0.9144米)长的RG58电缆线&#xff0c;并且在前端测量信号路径与返回路径之间的阻抗。那么测得的阻抗是多少&#xff1f;当然…

探索C语言中的联合体与枚举:数据多面手的完美组合!

​ ✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C语言学习 贝蒂的主页&#xff1a;Betty‘s blog 1. 联合体的定义 联合体又叫共用体&#xff0c;它是一种特殊的数据类型&…

Flomesh 发布 Pipy 0.99.1

值此新春佳节来临之际 &#xff0c;我们很高兴地宣布 Pipy 0.99.1 版本 的发布&#xff0c;此次更新带来了多项重要特性和改进&#xff0c;进一步增强了 Pipy 的功能性和灵活性。 新特性与改进&#xff1a; 增加了对 BPF (Berkeley Packet Filter) 的支持&#xff0c;包括加载…

Webstorm安装了vue脚手架后终端输入vue报错解决方法

当我们初学Vue的时候&#xff0c;刚安装完Vue脚手架之后&#xff0c;输入vue报错&#xff0c;是因为webstorm终端受限制了。 vue: 无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\vue.ps1&#xff0c;因为在此系统上禁止运行脚本。 解决方案如下&#xff1a; 通过…

51单片机之数码管显示表白数字篇

朝菌不知晦朔 蟪蛄不知春秋 眼界决定境界 CSDN 请求进入专栏 是否进入《51单片机专栏》? 确定 目录 数码管的简介 数码管引脚定义 数码管的原理图 74HC245 代码实现 静态数码管的显示 动态数码管的显示 数码管实现表白画面 数码管的简介 L…

【Unity】重力场中的路径预测方法

前言 笔者前些天参加完了一场72小时的GameJam游戏开发比赛。这次比赛的主题是“探索”&#xff0c;笔者做了一个名为《探索者号》的探索宇宙的游戏&#xff08;游戏名一开始叫做《星际拾荒者》&#xff0c;但这不重要&#xff09;。 在开发过程中&#xff0c;笔者遇到了一些问…

2 月 7 日算法练习- 数据结构-并查集

并查集 并查集是一种图形数据结构&#xff0c;用于存储图中结点的连通关系。 每个结点有一个父亲&#xff0c;可以理解为“一只伸出去的手”&#xff0c;会指向另外一个点&#xff0c;初始时指向自己。 一个点的根节点是该点的父亲的父亲的的父亲&#xff0c;直到某个点的父亲…

探索NLP中的N-grams:理解,应用与优化

简介 n-gram[1] 是文本文档中 n 个连续项目的集合&#xff0c;其中可能包括单词、数字、符号和标点符号。 N-gram 模型在许多与单词序列相关的文本分析应用中非常有用&#xff0c;例如情感分析、文本分类和文本生成。 N-gram 建模是用于将文本从非结构化格式转换为结构化格式的…

Elasticsearch(四)

是这样的前面的几篇笔记&#xff0c;感觉对我没有形成知识体系&#xff0c;感觉乱糟糟的&#xff0c;只是大概的了解了一些基础知识&#xff0c;仅此而已&#xff0c;而且对于这技术栈的学习也是为了在后面的java开发使用&#xff0c;但是这里的API学的感觉有点乱&#xff01;然…

[VulnHub靶机渗透] dpwwn: 1

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

接口测试--参数实现MD5加密签名规则

最近有个测试接口需求&#xff0c;接口有签名检查&#xff0c;签名规范为将所有请求参数按照key字典排序并连接起来进行md5加密&#xff0c;格式是&#xff1a;md5(bar2&baz3&foo1),得到签名&#xff0c;将签名追加到参数末尾。由于需要对参数进行动态加密并且做压力测…

有道ai写作,突破免费限制,无限制使用

预览效果 文末提供源码包及apk下载地址有道ai写作python版 import hashlib import time import json import ssl import base64 import uuidfrom urllib.parse import quote import requests from requests_toolbelt.multipart.encoder import MultipartEncoder from Crypto.C…

11 串口发送应用之使用状态机实现多字节数据发送

1. 使用串口发送5个字节数据到电脑 uart协议规定&#xff0c;发送的数据位只能是6&#xff0c;7&#xff0c;8位&#xff0c;如果数据位不符合&#xff0c;接收者接收不到数据。所以我们需要将40位数据data分为5个字节数据分别发送&#xff0c;那么接收者就能通过uart协议接收…

Mobile ALOHA 2: An Enhanced Low-Cost Hardware for Bimanual Teleoperation

文章目录 1. Mobile ALOHA 11.1 项目地址 2. Mobile ALOHA 22.1 相关链接2.2 Whats upgraded in II ? Reference Stanford 最新家务机器人 1. Mobile ALOHA 1 Mobile ALOHA: Learning Bimanual Mobile Manipulation with Low-Cost Whole-Body Teleoperation 1.1 项目地址 htt…

CoreSight学习笔记

文章目录 1 Components1.1 ROM Table 2 使用场景2.1 Debug Monitor中断2.1.1 参考资料 2.2 Programming the cross halt2.2.1 编程实现2.2.2 参考资料 2.3 CTI中断2.3.1 编程实现2.3.1.1 准备工作2.3.1.2 触发中断2.3.1.3 中断响应 2.3.2 参考资料 1 Components 1.1 ROM Table…

力扣热门100题 - 4.寻找两个正序数组的中位数

力扣热门100题 - 4.寻找两个正序数组的中位数 题目描述&#xff1a;示例&#xff1a;提示&#xff1a;解题思路&#xff1a;代码&#xff1a; 题目链接&#xff1a;4.寻找两个正序数组的中位数 题目描述&#xff1a; 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&a…

【golang】23、gorilla websocket 源码:examples、数据结构、流程

文章目录 一、examples1.1 echo1.1.1 server.go1.1.2 client.go 1.2 command1.2.1 功能和启动方式1.2.2 home.html1.2.3 main.go 1.3 filewatch1.3.1 html1.3.2 serveHome 渲染模板1.3.3 serveWs1.3.4 writer() 1.4 buffer pool1.4.1 server1.4.2 client 1.5 chat1.5.1 server1…

掌握虚拟化与网络配置之道:深入浅出VMware及远程管理技巧

目录 虚拟机介绍 虚拟机的关键字 服务器架构的发展 为什么用虚拟机VMware 虚拟机和阿里云的区别 功能角度 价格因素 应用场景 优势方面 找到windows的服务管理 配置VMware 关于VMware安装的几个服务 vmware如何修改各种网络配置 关于NAT的详细信息(了解) NAT(网…

【芯片设计- RTL 数字逻辑设计入门 11 -- 移位运算与乘法】

请阅读【嵌入式开发学习必备专栏 】 文章目录 移位运算与乘法Verilog Codeverilog 拼接运算符&#xff08;{}&#xff09;Testbench CodeVCS 波形仿真 问题小结 移位运算与乘法 已知d为一个8位数&#xff0c;请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输…