算法自学__背包动态规划

news2024/9/24 23:25:56

例1 P5020 [NOIP2018 提高组] 货币系统

题目描述

在网友的国度中共有 n n n 种不同面额的货币,第 i i i 种货币的面额为 a [ i ] a[i] a[i],你可以假设每一种货币都有无穷多张。为了方便,我们把货币种数为 n n n、面额数组为 a [ 1.. n ] a[1..n] a[1..n] 的货币系统记作 ( n , a ) (n,a) (n,a)

在一个完善的货币系统中,每一个非负整数的金额 x x x 都应该可以被表示出,即对每一个非负整数 x x x,都存在 n n n 个非负整数 t [ i ] t[i] t[i] 满足 a [ i ] × t [ i ] a[i] \times t[i] a[i]×t[i] 的和为 x x x。然而, 在网友的国度中,货币系统可能是不完善的,即可能存在金额 x x x 不能被该货币系统表示出。例如在货币系统 n = 3 n=3 n=3, a = [ 2 , 5 , 9 ] a=[2,5,9] a=[2,5,9] 中,金额 1 , 3 1,3 1,3 就无法被表示出来。

两个货币系统 ( n , a ) (n,a) (n,a) ( m , b ) (m,b) (m,b) 是等价的,当且仅当对于任意非负整数 x x x,它要么均可以被两个货币系统表出,要么不能被其中任何一个表出。

现在网友们打算简化一下货币系统。他们希望找到一个货币系统 ( m , b ) (m,b) (m,b),满足 ( m , b ) (m,b) (m,b) 与原来的货币系统 ( n , a ) (n,a) (n,a) 等价,且 m m m 尽可能的小。他们希望你来协助完成这个艰巨的任务:找到最小的 m m m

输入格式

输入文件的第一行包含一个整数 T T T,表示数据的组数。

接下来按照如下格式分别给出 T T T 组数据。 每组数据的第一行包含一个正整数 n n n。接下来一行包含 n n n 个由空格隔开的正整数 a [ i ] a[i] a[i]

输出格式

输出文件共有 T T T 行,对于每组数据,输出一行一个正整数,表示所有与 ( n , a ) (n,a) (n,a) 等价的货币系统 ( m , b ) (m,b) (m,b) 中,最小的 m m m

样例 #1

样例输入 #1

2 
4 
3 19 10 6 
5 
11 29 13 19 17

样例输出 #1

2   
5

提示

在第一组数据中,货币系统 ( 2 , [ 3 , 10 ] ) (2, [3,10]) (2,[3,10]) 和给出的货币系统 ( n , a ) (n, a) (n,a) 等价,并可以验证不存在 m < 2 m < 2 m<2 的等价的货币系统,因此答案为 2 2 2。 在第二组数据中,可以验证不存在 m < n m < n m<n 的等价的货币系统,因此答案为 5 5 5

【数据范围与约定】

对于 100 % 100\% 100% 的数据,满足 1 ≤ T ≤ 20 , n , a [ i ] ≥ 1 1 ≤ T ≤ 20, n,a[i] ≥ 1 1T20,n,a[i]1

思路

给定的货币系统 ( n , a ) (n, a) (n,a),判断在 a a a中有哪些面额可以用其他的面额凑出来,删除掉这些面额后,剩下的面额数量即为最小的 m m m

这个题目本质上是一个完全背包。先将 a a a中面额从小到大排序。设状态dp[i][j]表示:用前i种面额,凑出金额j的所有方案中,用到最多的货币数。显然,如果一个货币面额j,其dp[n][j] > 1,则该面额可以被其他货币凑出;如果dp[n][j] == 1,则该面额不能被其他货币凑出。容易得到,状态转移方程为:
d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − a [ i ] ] + 1 ) dp[i][j] = {\rm{max}}(dp[i-1][j], dp[i-1][j-a[i]]+1) dp[i][j]=max(dp[i1][j],dp[i1][ja[i]]+1)

注意边界条件:
d p [ 0 ] [ j ] = { − i n f , j ≠ 0 0 , j = 0 dp[0][j] = \begin{cases} -inf, &j\ne 0\\ 0, &j=0 \end{cases} dp[0][j]={inf,0,j=0j=0
确保所有符合条件的状态都由 dp[0][0] 转移而来。

代码

#include<bits/stdc++.h>
using namespace std;

const int maxn = 105;

int T, n;
int M;
int a[maxn];
//滚动数组
int dp[25005];
int ans;

int main(){
	cin>>T;
	while(T--){
		cin>>n;
		M = -1;
		ans = 0;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			M = max(M, a[i]);
		}
		//边界条件
		memset(dp, 0x80, sizeof(dp));
		dp[0] = 0;
		for(int i=1;i<=n;i++){
			for(int j=a[i];j<=M;j++){
				dp[j] = max(dp[j], dp[j-a[i]]+1);
			}
		}
		for(int i=1;i<=n;i++){
			//统计不能凑出的货币面额的数量
			if(dp[a[i]]==1) ans++;
		}
		cout<<ans<<'\n';
	}
	return 0;
}

例2 P2946 [USACO09MAR]Cow Frisbee Team S

题目描述

老唐最近迷上了飞盘,约翰想和他一起玩,于是打算从他家的 N N N 头奶牛中选出一支队伍。

每只奶牛的能力为整数,第 i i i 头奶牛的能力为 R i R_i Ri 。飞盘队的队员数量不能少于 1 1 1、大于 N N N。一支队伍的总能力就是所有队员能力的总和。

约翰比较迷信,他的幸运数字是 F F F ,所以他要求队伍的总能力必须是 F F F 的倍数。请帮他

算一下,符合这个要求的队伍组合有多少?由于这个数字很大,只要输出答案对 1 0 8 10^8 108 取模的值。

输入格式

第一行:两个用空格分开的整数: N N N F F F

第二行到 N + 1 N+1 N+1 行:第 i + 1 i+1 i+1 行有一个整数 R i R_i Ri ,表示第 i i i 头奶牛的能力。

输出格式

第一行:单个整数,表示方案数对 1 0 8 10^8 108 取模的值。

样例 #1

样例输入 #1

4 5 
1 
2 
8 
2

样例输出 #1

3

提示

数据范围与约定

  • 对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 2000 1 \le N \le 2000 1N2000 1 ≤ F ≤ 1000 1 \le F \le 1000 1F1000 1 ≤ R i ≤ 1 0 5 1 \le R_i \le 10^5 1Ri105

思路

这道题实质上是01背包。定义状态dp[i][j]表示:仅考虑前i头牛,凑出总能力值在模F的条件下为j方案数。显然,这道题目的最终答案对应了状态dp[N][0]。由于我们在选择牛时,仅需要考虑总能力模F下的值,所以我们可以在处理输入时,可以令所有的牛的能力值模F

状态转移方程为:
d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j + F − a [ i ] ] dp[i][j] = dp[i-1][j] + dp[i-1][j+F-a[i]] dp[i][j]=dp[i1][j]+dp[i1][j+Fa[i]]
解释:对于我们当前遍历的牛i,其在一个方案中:

  • 不选,对应dp[i-1][j],即用前i-1头牛凑出模Fj的总能力值。
  • 选,对应dp[i-1][j+F-a[i]],即加上这头牛后,凑出模Fj的总能力值。

对于边界条件,我们可以首先初始化第1头牛的情形:

  • 不选,总能力值为0,dp[1][0] = 1。注意到,这种情形是不合理的,所以在最终的答案中需要减去。
  • 选,总能力值为a[i],dp[1][a[i]] = 1

代码

#include<bits/stdc++.h>
using namespace std;

const int p = 1e8;
const int maxn = 2005;
const int maxf = 1005;

int dp[2][maxf];
int N, F;
int a[maxn];
int cnt = 0;

int main(){
	cin>>N>>F;
	for(int i=1;i<=N;i++){
		cin>>a[i];
		a[i] = a[i]%F;
	}
	dp[cnt^1][a[1]] = 1;
	dp[cnt^1][0] = 1;
	for(int i=2;i<=N;i++){
		for(int j=0;j<F;j++){
			dp[cnt][j] = (dp[cnt^1][j]+dp[cnt^1][(j+F-a[i])%F])%p;
		}
		cnt = cnt^1;
	}
	cout<<dp[cnt^1][0]-1;
	return 0;
}

例3 P1156 垃圾陷阱

垃圾陷阱

题目描述

卡门――农夫约翰极其珍视的一条 Holsteins 奶牛――已经落了到 “垃圾井” 中。“垃圾井” 是农夫们扔垃圾的地方,它的深度为 D D D 2 ≤ D ≤ 100 2 \le D \le 100 2D100)英尺。

卡门想把垃圾堆起来,等到堆得高度大等于于井的深度时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。

每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间。

假设卡门预先知道了每个垃圾扔下的时间 t t t 1 ≤ t ≤ 1000 1 \le t \le 1000 1t1000),以及每个垃圾堆放的高度 h h h 1 ≤ h ≤ 25 1 \le h \le 25 1h25)和吃进该垃圾能维持生命的时间 f f f 1 ≤ f ≤ 30 1 \le f \le 30 1f30),要求出卡门最早能逃出井外的时间,假设卡门当前体内有足够持续 10 10 10 小时的能量,如果卡门 10 10 10 小时内(不含 10 10 10 小时,维持生命的时间同)没有进食,卡门就将饿死。

输入格式

第一行为两个整数, D D D G G G 1 ≤ G ≤ 100 1 \le G \le 100 1G100), G G G为被投入井的垃圾的数量。

第二到第 G + 1 G+1 G+1 行每行包括三个整数: T T T 1 ≤ T ≤ 1000 1 \le T \le 1000 1T1000),表示垃圾被投进井中的时间; F F F 1 ≤ F ≤ 30 1 \le F \le 30 1F30),表示该垃圾能维持卡门生命的时间;和 H H H 1 ≤ H ≤ 25 1 \le H \le 25 1H25),该垃圾能垫高的高度。

输出格式

如果卡门可以爬出陷阱,输出一个整数,表示最早什么时候可以爬出;否则输出卡门最长可以存活多长时间。

样例 #1

样例输入 #1

20 4
5 4 9
9 3 2
12 6 10
13 1 1

样例输出 #1

13

思路

这道题可以用01背包的思路解决。定义状态dp[i][j]表示:仅考虑前i个垃圾,奶牛到达高度j最长的存活时间

对于一个垃圾i,我们有吃或不吃两种选择:

  • 吃,则状态转移方程为:
    d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] ,   d p [ i − 1 ] [ j ] + t r a s h [ i ] . f ) dp[i][j] = {\rm max}(dp[i][j],\ dp[i-1][j]+trash[i].f) dp[i][j]=max(dp[i][j], dp[i1][j]+trash[i].f)
    可以看出,状态dp[i][j]由状态dp[i-1][j]转移而来。为了使这个转移合法,必须保证奶牛在状态dp[i-1][j]的最长存活时间足够支撑它吃到垃圾i即:
    d p [ i − 1 ] [ j ] ≥ t r a s h [ i ] . t dp[i-1][j] \ge trash[i].t dp[i1][j]trash[i].t
  • 不吃,则状态转移方程为:
    d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] ,   d p [ i − 1 ] [ j − t r a s h [ i ] . h ] ) dp[i][j] = {\rm max}(dp[i][j],\ dp[i-1][j-trash[i].h]) dp[i][j]=max(dp[i][j], dp[i1][jtrash[i].h])
    可以看出,状态dp[i][j]由状态dp[i-1][j-trash[i].h]转移而来。为了使这个转移合法,必须保证奶牛在状态dp[i-1][j-trash[i].h]的最长存活时间足够支撑它吃到垃圾i,且j-trash[i].h >= 0,即:
    ( d p [ i − 1 ] [ j ] ≥ t r a s h [ i ] . t )   & &   ( j − t r a s h [ i ] . h ≥ 0 ) (dp[i-1][j] \ge trash[i].t)\ \&\&\ (j-trash[i].h\ge 0) (dp[i1][j]trash[i].t) && (jtrash[i].h0)

考虑初始状态:
d p [ 0 ] [ j ] = { 10 , j = 0 − i n f , j ≠ 0 dp[0][j]= \begin{cases} 10,&j=0\\ -inf,&j\ne0 \end{cases} dp[0][j]={10,inf,j=0j=0
所以,我们可以将dp[][]中的每个元素初始化为-inf,然后再令dp[0][0]10

代码

#include<bits/stdc++.h>
using namespace std;

const int maxn = 105;
const int inf = 0x7f7f7f7f;

struct TRASH{
	int t;
	int f;
	int h;
	bool operator<(const TRASH& a)const{
		return t<a.t;
	}
};

int D, G;
TRASH trash[maxn];
int dp[maxn][maxn];
int maxh=-1, maxt=-1; 
int ans = 0x7f7f7f7f;

int main(){
	cin>>D>>G;
	for(int i=1;i<=G;i++){
		cin>>trash[i].t>>trash[i].f>>trash[i].h;
	}
	sort(trash+1, trash+1+G);
	memset(dp, 0x80, sizeof(dp));
	dp[0][0] = 10;
	for(int i=1;i<=G;i++){
		for(int j=0;j<=D;j++){
			//吃 
			if(dp[i-1][j]>=trash[i].t){
				dp[i][j] = max(dp[i][j], dp[i-1][j]+trash[i].f);
			}
			//不吃
			if(j>=trash[i].h && dp[i-1][j-trash[i].h]>=trash[i].t){
				dp[i][j] = max(dp[i][j], dp[i-1][j-trash[i].h]);
			} 
		}
	}
	for(int i=1;i<=G;i++){
		for(int j=0;j<=D;j++){
			if(dp[i][j]>=0){
				maxh = max(maxh, j);
				if(maxh>=D){
					ans = min(ans, trash[i].t);
				}
			}
			maxt = max(maxt, dp[i][j]);
		}
	}
	if(maxh>=D) cout<<ans;
	else cout<<maxt;
	return 0;
}

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

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

相关文章

unity 使用Vuforia扫描物体( ModelTarget 模型目标)

1、下载vuforia插件vufora 2、下载模型生成器Model Target Generator 3、将vuforia插件导入到unity &#xff0c;我使用的unity是2021版本&#xff0c;导出插件时&#xff0c;只显示有两个文件&#xff0c;导入后&#xff0c;会有一个弹框 让更新插件&#xff0c;点击updata&am…

【编程语言 · C语言 · calloc和realloc】

【编程语言 C语言 calloc和realloc】https://mp.weixin.qq.com/s?__bizMzg4NTE5MDAzOA&mid2247491544&idx1&sn72d8f9931cfa7ce7441a3248475ab619&chksmcfade321f8da6a374a5935bb46441a03a007c0589db6b8afa8c1991854d632a3201553e37b0b&payreadticketHGy…

[算法很美打卡第四天] 字符串篇(中)

文章目录 压缩字符串代码 判断两字符串的字符集是否相同代码 旋转词代码 反转单词代码 回文串验证代码 去掉字符串中连接出现的k次的0代码 压缩字符串 代码 package 每日算法学习打卡.算法打卡.八月份;public class test1 {public static void main(String[] args) {String s …

替换linux的文泉驿正黑fonts-wqy-zenhei字体 替换linux默认中文字体

WSL 怎么替换 linux 的文泉驿正黑 fonts-wqy-zenhei 字体 WSL 怎么替换 linux 默认中文字体 在 wsl 中默认是没有 gnome 界面或者 xface 的&#xff0c;但是我需要使用 wsl 开发 electron 或者使用 chrome 浏览器。这个时候系统就会调用默认的系统字体了。 我使用的是 debian…

国产分布式数据库——TDSQL性能分析工具

一、TDSQL概述 TDSQL是腾讯研发的一款兼容MySQL协议的国产分布式数据库&#xff0c;适用于大并发、高性能、大容量的OLTP类场景。TDSQL分为集中式和分布式版本&#xff0c;分布式版可支持分布式事务&#xff0c;但性能不如单机事务&#xff0c;性能会有一定的损耗&#xff0c;…

Android系统的进程管理(创建->优先级->回收)

一、进程的创建 1、概述 Android系统以Linux内核为基础&#xff0c;所以对于进程的管理自然离不开Linux本身提供的机制。例如&#xff1a; 通过fork来创建进行通过信号量来管理进程通过proc文件系统来查询和调整进程状态 等 对于Android来说&#xff0c;进程管理的主要内容…

EMC VNX1系列存储电池状态说明

SPS电池正常的状态为“Present”。 SPS电池故障时的状态为“Faulted”。 更换SPS后&#xff0c;SPS开始充电&#xff0c;此时状态显示为“Not Ready”状态。 充电完成后显示为Present状态。如果充电完成后状态前面有“F”标记&#xff0c;则需要重启对应的控制器以更新SPS…

2023年最新智能优化算法之——切诺贝利灾难优化器 (CDO),附MATLAB代码和文献

切诺贝利灾难优化器Chernobyl Disaster Optimizer (CDO)是H. Shehadeh于2023年提出的新型智能优化算法。该方法是受到切尔诺贝利核反应堆堆芯爆炸而来的启发。在CDO方法中&#xff0c;放射性的发生是由于核的不稳定性&#xff0c;核爆炸会发出不同类型的辐射。这些辐射中最常见…

vue2、vue3生命周期详解以及对比

文章目录 对比vue2-vue3vue3生命周期生命周期的主要阶段详情 vue2 生命周期生命周期钩子函数 总共11个 常用的8个按照这四个阶段我们对应有八个生命周期钩子函数vue生命周期使用场景 对比vue2-vue3 如果熟悉vue2的话&#xff0c;vue3信手拈来&#xff0c;看图 vue3生命周期 on…

Qt应用开发(基础篇)——滑块类 Slider、ScrollBar、Dial

一、前言 滑块类QScrollBar、QSlider和QDial继承于QAbstractSlider&#xff0c;父类主要拥有最大值、最小值、步长、当前值、滑块坐标等信息&#xff0c;滑动的时候触发包含值数据变化、滑块按下、滑块释放等信号。键盘包括左/上和右/下箭头键通过定义的singleStep改变当前值&a…

idea调节文字大小、日志颜色、git改动信息

idea调节菜单栏文字大小&#xff1a; 调节代码文字大小&#xff1a; 按住ctrl滚动滑轮可以调节代码文字大小&#xff1a; 单击文件即可在主窗口上打开显示&#xff1a; idea在控制台对不同级别的日志打印不同颜色 &#xff1a; “grep console”插件 点击某一行的时候&#x…

北方多地暴雨引思考:如何降低暴雨负面影响?

受今年第五号台风“杜苏芮”残余环流北上影响&#xff0c;北方多地这两天出现了大范围的强降雨。 7月31日晚上&#xff0c;国家防总办公室、应急管理部加密研判会商&#xff0c;与中国气象局、水利部会商研判&#xff0c;视频连线北京、天津、河北等重点省份&#xff0c;滚动分…

通用版Bubble_sort

❤博主CSDN:啊苏要学习 ▶专栏分类&#xff1a;C语言◀ C语言的学习&#xff0c;是为我们今后学习其它语言打好基础&#xff0c;C生万物&#xff01; 开始我们的C语言之旅吧&#xff01;✈ 目录 前言&#xff1a; 一.分析Bubble_sort 二.解决措施 三.模拟实现 前言&#xff…

LInux的安装(VMware,网卡设置,SSH连接工具)

Linux的安装 1、安装方式介绍 1.安装方式: 物理机安装:直接将操作系统安装到服务器硬件上 虚拟机安装:通过虚拟机软件安装 **虚拟机( Virtual Machine&#xff09;**指通过软件模拟的具有完整硬件系统功能、运行在完全隔离环境中的完整计算机系统。 2、安装Linux 在官网将…

VMWare vSphere 7.0.3环境通过PowerCLI批量发布openeuler22.03LTS系统虚拟机

本文尝试在VMWare vSphere 7.0.3环境中&#xff0c;通过PowerCLI批量发布openeuler22.03LTS系统虚拟机&#xff0c;以减轻维护人员的工作量。 一、在维护机上安装PowerCLI 1、点击以下链接&#xff0c;跳转到VMWarePowerCLI官方页面 VMware PowerCLI下载链接 2、点击下载链…

【Python】simplekml如何设置样式(解决simplekml样式不生效)

原文作者&#xff1a;我辈李想 版权声明&#xff1a;文章原创&#xff0c;转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、基本样式常用 二、共享样式三、全局样式1.结果2.代码 前言 simplekml是一个用于创建kml文件的库&#xff0c;里面提供了丰富的功能和…

【编程】典型题目:寻找数组第K大数(四种方法对比)

【编程】典型题目&#xff1a;寻找数组第K大数&#xff08;四种方法对比&#xff09; 文章目录 【编程】典型题目&#xff1a;寻找数组第K大数&#xff08;四种方法对比&#xff09;1. 题目2. 题解2.1 方法一&#xff1a;全局排序&#xff08;粗暴&#xff09;2.2 方法二&#…

数据结构-链表结构-双向链表

双向链表 双向链表的定义 双向链表也叫双链表&#xff0c;与单向链表不同的是&#xff0c;每一个节点有三个区域组成&#xff1a;两个指针域&#xff0c;一个数据域 前一个指针域&#xff1a;存储前驱节点的内存地址后一个指针域&#xff1a;存储后继节点的内存地址数据域&a…

Java开发中的------修改密码+忘记密码

目录 1.修改密码 客户端响应 前端vue 后端 controller层 ServiceImpl实现层 2.忘记密码 客户端响应 后端 controller层 serviceImpl实现层 本章需要准备&#xff1a;springcloud项目&#xff0c;依赖&#xff0c;数据库.... 数据库SQL SET FOREIGN_KEY_CHECKS0;-- -…

C++设计模式之责任链设计模式

C责任链设计模式 什么是责任链设计模式 责任链设计模式是一种行为型设计模式&#xff0c;它允许多个处理请求的对象串联起来&#xff0c;形成一个处理请求的链。每个对象都有机会处理请求&#xff0c;如果该对象不能处理请求&#xff0c;则将请求传递给链中的下一个对象。 该…