包子凑数(蓝桥杯,闫氏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.mfbz.cn/a/497022.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络——29ISP之间的路由选择:BGP

ISP之间的路由选择&#xff1a;BGP 层次路由 一个平面的路由 一个网络中的所有路由器的地位一样通过LS&#xff0c;DV&#xff0c;或者其他路由算法&#xff0c;所有路由器都要知道其他所有路由器&#xff08;子网&#xff09;如何走所有路由器在一个平面 平面路由的问题 …

Liunx安装Nacos

Liunx安装Nacos 1、镜像下载 curl -O https://github.com/alibaba/nacos/releases/download/2.3.1/nacos-server-2.3.1.tar.gz2、解压到指定目录 tar -zxvf nacos-server-2.3.1.tar.gz -C /usr/local3、进入bin文件启动startup.sh文件 cd /usr/local/nacos/binsh startup.s…

精灵传信系统 匿名性系统 支持网站+小程序双端源码

精灵传信支持在线提交发送短信&#xff0c;查看回复短信&#xff0c;在线购买额度&#xff0c;自定义对接易支付&#xff0c;设置违禁词&#xff0c;支持网站小程序双端。 项目 地 址 &#xff1a; runruncode.com/php/19720.html 环境要求: PHP > 73 MySQL>5.6 Ngi…

Redis中的客户端(三)

客户端 身份验证 客户端状态的authenticated属性用于记录客户端是否通过了身份验证: typedef struct redisClient {// ...int authenticated;// ... } redisClient;如果authnticated的值为0&#xff0c;那么表示客户端未通过身份验证&#xff1b;如果authenticated的值为1&a…

分布式处理

前言 大家好&#xff0c;我是jiantaoyab&#xff0c;这是我作为学习笔记原理篇的最后一章&#xff0c;一台计算机在数据中心里是不够的。因为如果只有一台计算机&#xff0c;我们会遇到三个核心问题。第一个核心问题&#xff0c;叫作垂直扩展和水平扩展的选择问题&#xff0c;…

两年测开经历分享的测试开发学习路线

路线大纲 该学习路线一共是7个阶段&#xff0c;循序渐进&#xff0c;学习路线相对比较平缓图片 阶段0 : 前言 路线特点 适用于想转行做功能测试与测试开发的同学 给出目标、学习建议、关键知识点、最优资源以及各类资源推荐&#xff08;视频、书籍、文档、项目、工具等&am…

在宝塔面板中,为自己的云服务器安装SSL证书,为所搭建的网站启用https(主要部分攻略)

前提条件 My HTTP website is running Nginx on Debian 10&#xff08;或者11&#xff09; 时间&#xff1a;2024-3-28 16:25:52 你的网站部署在Debain 10&#xff08;或者11&#xff09;的 Nginx上 安装单域名证书&#xff08;默认&#xff09;&#xff08;非泛域名&#xf…

【TB作品】MSP430G2553,超声波倒车雷达PCB,单片机,超声波SR04,键盘,oled,

题目 硬件&#xff1a;MSP430G2553、 SR04超声波传感器 、3*4键盘、 无源蜂鸣器、oled显示屏 软件 1 、实时显示测量得到的距离 2、按键设置一个报警门限数值&#xff0c;直接输入数值后确认 3、低于报警门限数值就开始报警&#xff0c;而且距离越近蜂鸣器的鸣叫频率越高 程序…

20240321-1-AB测试面试题

AB测试面试题 1. 介绍一下ABTest的步骤 ABtest就是为了测试和验证模型/项目的效果&#xff0c;在app/pc端设计出多个版本&#xff0c;在同一时间维度下&#xff0c;分别用组成相同/相似的群组去随机访问这些版本&#xff0c;记录下群组的用户体验数据和业务数据&#xff0c;最…

Xcode 15 Sandbox: rsync(xxxx) deny(1) file-write-create

设置里面搜索user 把User Script Sanboxing 改为NO 新版本的Xcode 15 编译报该错误 右侧工具栏 项目的workspace 和 pod的 space 都选择为15.0 即可

泛微E9 担当只能查看与自己相关的明细表数据,无关数据隐藏不显示

功能背景 我们在完成一些大型的任务时&#xff0c;会涉及到多个担当来分工&#xff0c;每个担当都有自己的工作范围&#xff0c;但是在担当确认自己的工作时&#xff0c;其他担当的工作内容需要保密。 实例 申请人在填报时&#xff0c;需要填写类型、项目名、担当&#xff0…

TOP100-回溯(二)

4.39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制…

windows安装jdk8

我们会在windows中通过Java代码去操作hadoop集群&#xff0c;因此我们需要在windows系统中配置java相关的环境&#xff0c;今天带着大家安装以下jdk8. 1.找到jdk8的安装文件 2.双击该文件进行安装 稍微等待一会儿&#xff08;30秒左右&#xff0c;有时时间会长些&#xff09; 安…

代码随想录第23天| 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 669. 修剪二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 你修剪的方式不对&#xff0c;我来给你纠正一下&#xff01;| LeetCode&#xff1a;669. 修剪二叉搜索树_哔哩哔哩_bilibili 给你二叉搜索树的根节点 root …

学点儿Java_Day12_IO流

1 IO介绍以及分类 IO: Input Output 流是一组有顺序的&#xff0c;有起点和终点的字节集合&#xff0c;是对数据传输的总称或抽象。即数据在两设备间的传输称为流&#xff0c;流的本质是数据传输&#xff0c;根据数据传输特性将流抽象为各种类&#xff0c;方便更直观的进行数据…

【I.MX6ULL移植】Ubuntu-base根文件系统移植

1.下载Ubuntu16.04根文件系统 http://cdimage.ubuntu.com/ 1 2 3 4 5 2.解压ubuntu base 根文件系统 为了存放 ubuntu base 根文件系统&#xff0c;先在 PC 的 Ubuntu 系统中的 nfs 目录下创建一个名为 ubuntu_rootfs 的目录&#xff0c;命令如下&#xff1a; 【注意&…

librdkafka的简单使用

文章目录 摘要kafka是什么安装环境librdkafka的简单使用生产者消费者 摘要 本文是Getting Started with Apache Kafka and C/C的中文版&#xff0c; kafka的hello world程序。 本文完整代码见仓库&#xff0c;这里只列出producer/consumer的代码 kafka是什么 本节来源&#…

C# 高级文件操作与异步编程探索(初步)

文章目录 文本文件的读写探秘StreamReader 类深度剖析StreamWriter 类细节解读编码和中文乱码的解决方案 二进制文件的读写BinaryReader 类全面解析BinaryWriter 类深度探讨 异步编程与C#的未来方向同步与异步&#xff1a;本质解读Task 的神奇所在async/await 的魔法 在现代编程…

NOIP,CSP-J,CSP-S——树

一、树 概念: 节点、深度、路径、边 树的直径 真题: 答案:B 答案:A 一个树的边是n-1 现在是m,所以m-(n-1)=m-n+1

Elasticsearch 向量搜索

目标记录 ["你好&#xff0c;我的爱人","你好&#xff0c;我的爱妻","你好&#xff0c;我的病人","世界真美丽"] 搜索词 爱人 预期返回 ["你好&#xff0c;我的爱人","你好&#xff0c;我的爱妻"] 示例代码…
最新文章