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

news2024/9/22 13:42:39

题目描述:

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

他发现这家包子铺有 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.coloradmin.cn/o/1552733.html

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

相关文章

解决:PytorchStreamWriter failed writing file data

文章目录 问题内容问题分析解决思路 问题内容 今天在炼丹的时候&#xff0c;我发现模型跑到140步的时候保存权重突然报了个问题&#xff0c;详细内容如下&#xff1a; Traceback (most recent call last):File "/public/home/dyedd/.conda/envs/diffusers/lib/python3.8…

uniapp输入框事件(防抖)

一、描述 在输入框输入内容或者说输入关键词的时候&#xff0c;往往都要进行做防抖处理。如果不做防抖&#xff0c;你输入什么&#xff0c;动态绑定的数据就会保持一致。这样不好吗&#xff0c;同步获取。有个业务场景&#xff0c;如果是搜索框&#xff0c;你每次一个字符&…

2024年第十届国际虚拟现实大会(ICVR 2024)即将召开!

会议面向虚拟现实、增强现实、人工智能等互联网新技术领域的专家及学者&#xff0c; 致力于共同促进国内外虚拟现实的发展与应用。 2014年至今&#xff0c;ICVR在全球新加坡&#xff0c;美国洛杉矶&#xff0c;中国成都&#xff0c;香港等国家及地区召开&#xff0c;面向虚拟现…

力扣面试150 二叉搜索树的最小绝对差 中序遍历

Problem: 530. 二叉搜索树的最小绝对差 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 录哥题解 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1) Code // 递归 class Solution {int ans Integer.MAX_VALUE;TreeNode pre;//一开…

C++的非类型模板参数与模板分离编译(模板显式实例化)

非类型模板参数与模板分离编译&#xff08;模板显式实例化&#xff09; 文章目录 非类型模板参数与模板分离编译&#xff08;模板显式实例化&#xff09;前言一、非类型模板参数二、模版分离编译1. 分离编译概念2. 模版的分离编译问题案例解决方法 总结 前言 ​ 本篇博客文章介…

vue2源码解析——Vue.set/$set方法如何给响应式对象添加属性

在Vue 2中需要向响应式对象添加新属性时&#xff0c;可以使用Vue.set或$set方法来实现。这两个方法的作用是向响应式对象添加属性并确保这个新属性也是响应式的。 为什么会有vue.set方法 Vue提供了Vue.set方法主要是为了解决在Vue 2.x 中动态添加属性时可能遇到的响应性问题。 …

八大技术趋势案例(区块链量子计算)

科技巨变,未来已来,八大技术趋势引领数字化时代。信息技术的迅猛发展,深刻改变了我们的生活、工作和生产方式。人工智能、物联网、云计算、大数据、虚拟现实、增强现实、区块链、量子计算等新兴技术在各行各业得到广泛应用,为各个领域带来了新的活力和变革。 为了更好地了解…

钡铼技术R40路由器助力智能船舶航行数据实时传输与分析

钡铼技术R40路由器在智能船舶领域的应用&#xff0c;对于航行数据的实时传输与分析具有重要意义。随着航运业的不断发展和智能化水平的提升&#xff0c;船舶航行数据的及时传输和有效分析对船舶的安全、运营效率等方面至关重要。而引入钡铼技术R40路由器&#xff0c;则可以实现…

前后端分离开发【Yapi平台】【Swagger注解自动生成接口文档平台】

前后端分离开发 介绍开发流程Yapi&#xff08;api接口文档编写平台&#xff09;介绍 Swagger使用方式1). 导入knife4j的maven坐标2). 导入knife4j相关配置类3). 设置静态资源映射4). 在LoginCheckFilter中设置不需要处理的请求路径 查看接口文档常用注解注解介绍 当前项目中&am…

Eclipse+Java+Swing实现斗地主游戏

一. 视频演示效果 java斗地主源码演示 ​ 二.项目结构 代码十分简洁&#xff0c;只有简单的7个类&#xff0c;实现了人机对战 素材为若干的gif图片 三.项目实现 启动类为Main类&#xff0c;继承之JFrame&#xff0c;JFrame 是 Java Swing 库中的一个类&#xff0c;用于创建窗…

Cisco Firepower FMCv修改管理Ip方法

FMCv 是部署在VMWARE虚拟平台上的FMC 部署完成后&#xff0c;如何修改管理IP 1 查看当前版本 show version 可以看到是for VMware 2 修改管理IP步骤 2.1 进入expert模式 expert2.2 进入超级用户 sudo su并输入密码 2.3 查看当前网卡Ip 2.4 修改Ip 命令&#xff1a; /…

Scala第十三章节(作为值的函数及匿名函数、柯里化、闭包及控制抽象以及计算器案例)

章节目标 掌握作为值的函数及匿名函数的用法了解柯里化的用法掌握闭包及控制抽象的用法掌握计算器案例 1.高阶函数介绍 Scala 混合了面向对象和函数式的特性&#xff0c;在函数式编程语言中&#xff0c;函数是“头等公民”&#xff0c;它和Int、String、Class等其他 类型处于…

Unity3d使用Jenkins自动化打包(Windows)(二)

文章目录 前言一、Unity工程准备二、Unity调取命令行实战一实战二实战三实战四实战五 总结 前言 自动化打包的价值在于让程序员更轻松地创建和管理构建工具链&#xff0c;提高编程效率&#xff0c;将繁杂的工作碎片化&#xff0c;变成人人&#xff08;游戏行业特指策划&#x…

ChatGPT 商业金矿(上)

原文&#xff1a;ChatGPT Business Goldmines 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第一章&#xff1a;为什么我写这本书 欢迎阅读《ChatGPT 多源收入&#xff1a;20 个利润丰厚的业务&#xff0c;任何人都可以在一周内使用 ChatGPT 开始》。我很高兴分享我…

C语言例4-32:利用for语句实现循环次数未知的例子

从键盘输入若干个整数&#xff0c;求其中的最大者和最小者&#xff0c;直到输入“0”为止 算法分析&#xff1a; 读取第一个整数i&#xff0c;并假设它是当前最大整数max&#xff0c;也是当前最小整数min当,则重复执行以下操作&#xff0c;若i<min&#xff0c;则mini;从键…

Java中读取html文件转成String,展示在浏览器

这里写目录标题 第一章1.1&#xff09;pom中引入依赖和html文件示例1.2&#xff09;使用hutool工具包读取html文件转为string1.3&#xff09;页面显示 第一章 1.1&#xff09;pom中引入依赖和html文件示例 引入hutool工具包依赖 <dependency><groupId>cn.hutool&…

华为防火墙配置指引超详细(包含安全配置部分)以USG6320为例

华为防火墙USG6320 华为防火墙USG6320是一款高性能、高可靠的下一代防火墙,适用于中小型企业、分支机构等场景。该防火墙支持多种安全功能,可以有效抵御网络攻击,保护网络安全。 目录 华为防火墙USG6320 1. 初始配置 2. 安全策略配置 3. 防火墙功能配置 4. 高可用性配…

iPhone用GPT替代Siri

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 个人IP&#xff1a;shigen 前一段时间&#xff0c;因为iCloud协议的更新&#xff0c;我的云盘空间无法正常…

Starrocks基于主机和容器的读写测试

背景介绍 在云原生时代&#xff0c;存算分离架构显然已经是当下大数据架构的必备选型&#xff0c;但是在不同的虚拟化计算资源&#xff08;主机、容器&#xff09;之上&#xff0c;是否能有差异点以及对于不同服务的性能损耗程度如何&#xff1f;来判断应该在什么样的场景下选…

Micron 256 GB DDR5-8800 MCR DIMM:适用于大型服务器的大型内存

美光本周宣布&#xff0c;它已经开始对其 256 GB multiplexer combined &#xff08;MCR&#xff09; DIMM 进行采样&#xff0c;这是该公司迄今为止容量最大的内存模块。这些全新的基于 DDR5 的 MCRDIMM 面向下一代服务器&#xff0c;特别是那些由英特尔至强可扩展“Granite R…