包子凑数(蓝桥杯,闫氏DP分析法)

题目描述:

小明几乎每天早晨都会在一家包子铺吃早餐。

他发现这家包子铺有 N 种蒸笼,其中第 i 种蒸笼恰好能放 Ai 个包子。

每种蒸笼都有非常多笼,可以认为是无限笼。

每当有顾客想买 X 个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有 X 个包子。

比如一共有 3 种蒸笼,分别能放 3、4和 5 个包子。

当顾客想买 11个包子时,大叔就会选 2 笼 3 个的再加 1 笼 5 个的(也可能选出 1 笼 3 个的再加 2 笼 4 个的)。

当然有时包子大叔无论如何也凑不出顾客想买的数量。

比如一共有 3 种蒸笼,分别能放 4、5和 6 个包子。

而顾客想买 7 个包子时,大叔就凑不出来了。

小明想知道一共有多少种数目是包子大叔凑不出来的。

输入格式:

第一行包含一个整数 N。

接下来 N 行,每行包含一个整数 Ai。

输出格式:

输出一个整数代表答案。

如果凑不出的数目有无限多个,输出INF。

数据范围:

1≤N≤100,
1≤Ai≤100

输入样例1:

2
4
5

输出样例1:

6

输入样例2:

2
4
6

输出样例2:

INF

样例解释

对于样例1,凑不出的数目包括:1, 2, 3, 6, 7, 11。
对于样例2,所有奇数都凑不出来,所以有无限多个。

前情提要:这道题目有关完全背包,01背包这两道题目,如果没看过这两道题目的题解大家可以去看看,能帮助理解这道题目。链接我也放到这里了,点击链接就行。

分析步骤:

  第一:看到题目我们就能明白,每一笼包子是可以选无数多笼的,只要次数不超过我们指定的个数,看看能组合出多少种组合来,最后判断一下有多少个数组合出来了,多少个数没有组合出来那么这就是答案。由此可以得出第一个特点:题目是 组合问题,是完全背包问题的变形:有几个物品,每个物品无限个,每个物品选任意个,能否凑到某个重量。

  第二:我们如何判断这个题目是否有无数个值会组合不出来呢?我们想一下什么样的就组合不出来,例如2,4,6最大公约数是2所以奇数组合不出来,因为他只能组合出gcd的倍数。例如30,60最大公约数是30所以只要不是30的倍数的就一定组合不出来,由此我们可以发现一些问题组合数和gcd有关,只要gcd不是1的话那么它就有无数种数组合不出来。这里用到裴蜀定理 ,任意两个数的组合必定是他们gcd的倍数,同样可以推广到更多数:如果这些数的gcd的d不是1那么有无数个数组合不出来

  第三:闫氏DP分析法:

  • 根据闫氏DP分析法我们可以知道dp问题可以将其分解为两个步骤:第一种是状态表示,第二种是状态计算。

  • 我们所有的背包问题都是围绕我们对于集合的定义来的,所以这个定义是非常重要的!!!我们将集合定义为:所有只从前i个包子中选择,数量为j的集合是否能够达到题目要求的包子数,是个bool数组。

  • 状态计算:由于完全背包是可以无限次的选择物品的,所以我们不能和01背包一样,只将其分解为选或者不选,因为它可以有很多很多种选择,可以不选,可以选一种,可以选两种...只要题目要求包子数量(背包体积)足够大就可以。

  • 如果他不选择包子 i 那么这种情况相当于从(1,i - 1)中选择数量不超过j的情况是一样的所以我们的表达式是:f[i-1][j]

  • 如果他选择物品 i 那么这样又该如何表示呢?我们并不知道他到底要选择几个物品,那应该怎么做呢?假如我们选择一个的话那么就应该写为f[i-1][j-vi];假如我们选择两个的话那么就应该写为f[i-1][j-2*vi];假如我们选择k个的话那么就应该写为f[i-1][j-k*vi],那么我们最终的答案就应该在这些集合之中。

  • 所以f(i,j)  = f(i-1 , j) || f(i-1 , j - v) || f(i-1 , j - 2v) || ........|| f(i-1 , j - (j/v)*v);

  • 所以f(i,j-v) = f(i-1 , j - v) || f(i-1 , j - 2*v) || f(i-1 , 3*v) || ........f(i-1 , j - (j/v)*v);

  • 由上述两个式子,我们可以知道如果将 j 替换成 j-vi 两个式子非常相似。f[ i ] [ j ] = f[ i -1][ j ] || f[ i ][ j - vi ] ;

  第四:书写主函数,构建整体框架:

  1. 输入值,并且根据裴蜀定理求出最大公约数看看是不是1,如果不是1那么必定有无数个值组合不出来,那么直接输出INF。初始化一下我们的f数组全部赋值为0,初始化我们的f[0][0] = true。为什么?根据我们对集合的定义来分析:只从前i个包子中选择,数量为j的集合是否能够达到题目要求的包子数。那么f[0][0]代表前0个包子中选择,数量为0的集合是可能的所以初始化为true。

    for(int i = 1 ; i <= n ; ++ i){for(int j = 0 ; j <= 10000 ; ++ j){f[i][j] = f[i-1][j] || (j >= arr[i] ? f[i][j - arr[i]] : false) ;}}
  2. d==1 的话我们就进入双重for循环。第一个for就是包子种类,第二个for就是包子数量。那么问题来了。我们怎么确定数量最大值就是10000呢?那么当qcd为1时,最大不能表示出来的数必定有个上界,因为两个数a,b(当gcd=1时),最大不能表示出数是:(a-1)(b-1)-1。当数字更多的时候,这个上界必然更小(可选的数字变多了),而99和98是100内最大的互质的数,所以这个上界选择10000。

  3. 我们之前分析出了f[ i ] [ j ] = f[ i -1][ j ] || f[ i ][ j - vi ] ;但是注意一个问题:选择一个,选择两个,是在所需包子数大于我们的这一笼包子数的情况下才可以选假如所需包子数都要小于这一笼包子数的话就不可以选了!所以我们选择了用三目运算符 (j >= arr[i] ? f[i][j - arr[i]] : false) ;这句话的意思是如果 j >= arr[i] 是对的话那么则返回f[i][j - arr[i]] ;如果不对则返回false,那么f[ i ] [ j ] = f[ i -1][ j ] || f[ i ][ j - vi ]这就是错了就代表组合不出这个数。

  4. 最后我们只需要在遍历一遍,看看哪些数是组合不出来的,组合不出来就res++。

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N = 110 ;int n ; 
bool f[N][10010];
int arr[N];int gcd(int a , int b){return b ? gcd(b,a%b):a;
}int main()
{cin>>n;int d = 0;for(int i = 1 ; i <= n ; ++i){cin>>arr[i];d = gcd(d,arr[i]);}memset(f, 0, sizeof f);f[0][0] = true;if(d != 1) cout<<"INF"<<endl;else{for(int i = 1 ; i <= n ; ++ i){for(int j = 0 ; j <= 10000 ; ++ j){f[i][j] = f[i-1][j] || (j >= arr[i] ? f[i][j - arr[i]] : false) ;}}int res = 0;for(int i = 0 ; i <= 10000 ; i ++){if(!f[n][i]) res ++;}cout<<res;
}return 0;
}

01背包从后往前,完全背包从前往后!!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

爱上数据结构:顺序表和链表

一、线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条…

netty rpc框架 即时通讯

Netty是Java领域有名的开源网络库&#xff0c;特点是高性能和高扩展性&#xff0c;因此很多流行的框架都是基于它来构建的&#xff0c;比如我们熟知的Dubbo、Rocketmq、Hadoop等&#xff0c;针对高性能RPC&#xff0c;一般都是基于Netty来构建&#xff0c;比如sock-bolt。总之一…

2024-3-28 市场情绪强修复

这一轮退潮负反馈都修复了&#xff0c; 艾艾精工 博信股份 安奈尔 永悦科技 大理药业 &#xff0c;高新发展 也补跌了&#xff0c;收尸队也干活了&#xff0c;情绪不修复不接力得最好写照。这轮周期 宁科生物 已经7板&#xff0c;已经追平了 博信股份7板&#xff0c;看明天溢…

18.字面量

文章目录 一、字面量二、区分技巧三、扩展&#xff1a; /t 制表符 一、字面量 在有些资料&#xff0c;会把字面量说成常量、字面值常量&#xff0c;这种叫法都不是很正确&#xff0c;最正确的叫法还是叫做&#xff1a;字面量。 作用&#xff1a;告诉程序员&#xff0c;数据在…

环信IM集成教程---消息转发合并转发的实现

前言 在发送消息体系中&#xff0c;转发消息是一个重要的环节&#xff0c;可以单条转发也可以合并转发。本文教大家在接入环信IM过程中如何实现单条转发&#xff0c;合并转发消息功能&#xff0c;同时举例一些容易踩坑的位置&#xff0c;以便大家尽快顺利的实现转发消息功能。…

高效 CUDA 调试:将 NVIDIA Compute Sanitizer 与 NVIDIA 工具扩展结合使用并创建自定义工具

高效 CUDA 调试&#xff1a;将 NVIDIA Compute Sanitizer 与 NVIDIA 工具扩展结合使用并创建自定义工具 NVIDIA Compute Sanitizer 是一款功能强大的工具&#xff0c;可以节省您的时间和精力&#xff0c;同时提高 CUDA 应用程序的可靠性和性能。 在 CUDA 环境中调试代码既具有挑…

Exception in thread “main“ com.fasterxml.jackson.databind.JsonMappingException:

问题&#xff1a;jaskson反序列化超出最大长度 Caused by: com.fasterxml.jackson.core.exc.StreamConstraintsException: String length (5043456) exceeds the maximum length (5000000) 场景&#xff1a;前端传递过大base64 原因&#xff1a; jaskon默认已经限制了最大长…

20个超实用Python魔法方法

大家好&#xff01;今天我们要一起探索Python世界的神秘角落——那些被称为“魔法方法”的特殊成员方法。它们就像是编程中的魔法咒语&#xff0c;赋予你的类各种神奇特性&#xff0c;让你的代码更加简洁、强大且有趣味&#xff01; __init__&#xff1a;这是每个对象出生时都要…

安卓利用CameraX 拍照获这张照片的exif信息

一、首先导入相关权限 <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE" /><uses-featureandroid:name"android.hardware.camera"android:required"true" /><uses-permission android:name"andro…

蓝桥杯练习题总结(三)线性dp题(摆花、数字三角形加强版)

目录 一、摆花 思路一&#xff1a; 确定状态&#xff1a; 初始化&#xff1a; 思路二&#xff1a; 确定状态&#xff1a; 初始化&#xff1a; 循环遍历&#xff1a; 状态转移方程&#xff1a; 二、数字三角形加强版 一、摆花 题目描述 小明的花店新开张&#xff0c;为了吸…

Uni-app/Vue/Js本地模糊查询,匹配所有字段includes和some方法结合使用e

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1.第一步 需要一个数组数据 {"week": "全部","hOutName": null,"weekendPrice": null,"channel": "门市价","hOutId": 98,"cTime": "…

【Redis】Redis 内存管理,Redis事务,bigkey和hotkey

目录 Redis 内存管理 缓存数据设置过期时间&#xff1f; Redis 是如何判断数据是否过期的呢&#xff1f; 过期删除策略 内存淘汰机制 主从模式下对过期键的处理&#xff1f; LRU和LFU的区别 Redis事务 定义和原理 Redis 事务的注意点&#xff1f; 为什么不支持回滚&a…

SQLite数据库文件损坏的可能几种情况(一)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十三&#xff09; 下一篇&#xff1a;SQLite使用的临时文件&#xff08;二&#xff09; 概述 SQLite数据库具有很强的抗损坏能力。如果应用程序崩溃&#xff0c…

指针数组的有趣程序【C语言】

文章目录 指针数组的有趣程序指针数组是什么&#xff1f;指针数组的魅力指针数组的应用示例&#xff1a;命令行计算器有趣的颜色打印 结语 指针数组的有趣程序 在C语言的世界里&#xff0c;指针是一种强大的工具&#xff0c;它不仅能够指向变量&#xff0c;还能指向数组&#…

HBase Shell基本操作

一、进入Hbase Shell客户端 先在Linux Shell命令行终端执行start-dfs.sh脚本启动HDFS&#xff0c;再执行start-hbase.sh脚本启动HBase。如果Linux系统已配置HBase环境变量&#xff0c;可直接在任意目录下执行hbase shell脚本命令&#xff0c;就可进入HBase Shell的命令行终端环…

Unity Mobile Notifications推送问题

1.在部分机型点击通知弹窗进不去游戏 把这里改成自己的Activity 2.推送的时候没有横幅跟icon红点 主要是第一句话 注册的时候选项可以选择 defaultNotificationChannel new AndroidNotificationChannel(“default_channel”, “Default Channel”, “For Generic notifica…

LinkedIn 互联网架构扩展简史

LinkedIn成立于 2003 年&#xff0c;其目标是连接到您的网络以获得更好的工作机会。第一周只有 2,700 名会员。时间快进了很多年&#xff0c;LinkedIn 的产品组合、会员基础和服务器负载都取得了巨大的增长。 如今&#xff0c;LinkedIn 在全球运营&#xff0c;拥有超过 3.5 亿会…

今日AI热点:科技前沿新动态

引言&#xff1a; 人工智能领域日新月异&#xff0c;每天都有令人振奋的新进展。从苹果到谷歌&#xff0c;从OpenAI到Meta&#xff0c;各大科技巨头纷纷推出创新产品和技术&#xff0c;不断推动着人工智能的发展。让我们一起来看看今日AI热点&#xff0c;探索这个充满活力和激情…

C++从入门到精通——命名空间

命名空间 前言一、命名空间引例什么是命名空间 二、命名空间定义正常的命名空间定义嵌套的命名空间多个相同名称的命名空间 三、命名空间使用加命名空间名称及作用域限定符使用using将命名空间中某个成员引入使用using namespace 命名空间名称引用引用命名空间和引用头文件有什…

Mac安装minio

Mac安装minio 本文介绍使用 mac 安装 MinIO。 所有软件安装优先参考官网&#xff1a;MinIO Object Storage for MacOS — MinIO Object Storage for MacOS #使用 brew 安装 minio brew install minio/stable/minio#找到 minio tong ~ $ brew list minio /opt/homebrew/Cella…