[NOIP 2003] 栈(三种方法:DP、数论、搜索)

news2024/11/17 3:48:25

[NOIP2003 普及组] 栈

题目背景

栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表。

栈有两种最重要的操作,即 pop(从栈顶弹出一个元素)和 push(将一个元素进栈)。

栈的重要性不言自明,任何一门数据结构的课程都会介绍栈。宁宁同学在复习栈的基本概念时,想到了一个书上没有讲过的问题,而他自己无法给出答案,所以需要你的帮忙。

题目描述

宁宁考虑的是这样一个问题:一个操作数序列, 1 , 2 , … , n 1,2,\ldots ,n 1,2,,n(图示为 1 到 3 的情况),栈 A 的深度大于 n n n

现在可以进行两种操作,

  1. 将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的 push 操作)
  2. 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的 pop 操作)

使用这两种操作,由一个操作数序列就可以得到一系列的输出序列,下图所示为由 1 2 3 生成序列 2 3 1 的过程。

(原始状态如上图所示)

你的程序将对给定的 n n n,计算并输出由操作数序列 1 , 2 , … , n 1,2,\ldots,n 1,2,,n 经过操作可能得到的输出序列的总数。

输入格式

输入文件只含一个整数 n n n 1 ≤ n ≤ 18 1 \leq n \leq 18 1n18)。

输出格式

输出文件只有一行,即可能输出序列的总数目。

样例 #1

样例输入 #1

3

样例输出 #1

5

提示

【题目来源】

NOIP 2003 普及组第三题

方法一:动态规划DP

1、思路

这道题一眼给我们的感觉就是方案数太多了,而且利用暴力DFS是可以解决的,但是效率太慢。此时我们就应该思考一下DP了。

(1)状态表示

f ( i , j ) f(i,j) f(i,j)表示的是,队列中的有 i i i个元素,栈中有 j j j个元素的时候,能够输出的栈序列总数。

(2)状态转移

一般情况下,我们面临的只有两种方式:

要么让队列中的元素入栈: f ( i − 1 , j + 1 ) f(i-1,j+1) f(i1,j+1)

要么就是让队列中的元素不动,栈中的元素出队。
所以方程是: f ( i , j − 1 ) f(i,j-1) f(i,j1)

f ( i , j ) = { f ( i − 1 , j + 1 ) + f ( i , j − 1 ) j ≥ 1 f ( i , j − 1 ) 0 ≤ j < 1 f(i,j)= \begin{cases} f(i-1,j+1)+f(i,j-1)&j\geq 1\\ f(i,j-1) &0\leq j<1 \end{cases} f(i,j)={f(i1,j+1)+f(i,j1)f(i,j1)j10j<1

(3)循环设计

循环的设计是为了保证每次利用状态转移方程求解问题的时候,方程右侧的子问题已经在此之前正确的求解。

如果说的高端一些,就是我们的循环设计要满足拓扑排序

我们看方程:
在算 f ( i , j ) f(i,j) f(i,j)的时候,我们要知道的子问题答案有:

f ( i − 1 , j + 1 ) f(i-1,j+1) f(i1,j+1) f ( i , j − 1 ) f(i,j-1) f(i,j1)

所以我们的外循环枚举 i i i,内循环枚举 j j j。如果反过来的话,我们会发现,我们含 j + 1 j+1 j+1的那一项无法在此之前算出。

(4)初末状态

初始状态是为了初始化最小的子问题,末尾状态是为了表示我们的答案。

我们的初始状态即当栈中的元素是j个,队列中的元素是0个的时候,我们只能出栈。此时只有1种序列。

还有就是当我们的队列中的元素只有1个,我们的栈中元素的个数是0的时候,我们此时的序列也是只有一种。

我们的最终状态是,队列中的元素个数是n,栈中的元素个数是0。即f[n][0]

2、代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=20;
int f[N][N];
int main()
{
    int n;
    cin>>n;
    f[1][0]=1;
    for(int i=0;i<=n;i++)
        f[0][i]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
        {
            if(j!=0)
                f[i][j]=f[i-1][j+1]+f[i][j-1];
            else
                f[i][j]=f[i-1][j+1];
        }
    }
    cout<<f[n][0]<<endl;
    return 0;
}

方法二:DFS+记忆数组——记忆化搜索

记忆化搜索其实可以将动规的循环做法改为了函数递归的做法。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=20;
int f[N][N];
int n;
int dfs(int i,int j)
{
    if(f[i][j])return f[i][j];
    if(i==0) return 1;
    if(j==0&&i==1)return 1;
    
    if(j>=1)f[i][j]=dfs(i-1,j+1)+dfs(i,j-1);
    else f[i][j]=dfs(i-1,j+1);

    return f[i][j];
}
int main()
{
    int n;
    cin>>n;
    cout<<dfs(n,0)<<endl;
    return 0;
}

方法三:数论——卡特兰数

如果有的同学不知道什么是卡特兰数的话,建议读者先去看一下作者在算法专栏中对卡特兰数的讲解。
传送门:

算法专栏——组合数之卡特兰数详解

1、为什么能用卡特兰数

我们发现卡特兰数的使用场景有以下的特点:
(1)只有两种操作
(2)过程中,其中一种操作的次数要大于等于另外一种操作的操作次数。最终两者的操作次数相等。

当满足上述特点的时候,就可以使用卡特兰数。

而我们这道题就两个操作,一个是入栈,一个是出栈,出栈的前提是栈中有元素。所以出栈的次数不能超过入栈的次数。但是最终我们的栈中元素要全部出栈。

所以满足上面的两个要求。

因此,可以使用卡特兰数。

2、代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll c(int a,int b)
{
    ll res=1;
    for(int i=1,j=a;i<=b;i++,j--)
    {
        res*=j;
        res/=i;
    }
    return res;
}
int main()
{
    int n;
    cin>>n;
    cout<<c(2*n,n)-c(2*n,n-1)<<endl;
}

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

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

相关文章

5 个必须尝试的无代码应用

无代码软件让任何人无需了解编程语言即可构建产品、网站和应用程序。Editor XWix 发布了Editor X&#xff0c;这是一款无需编写任何 CSS &#xff08;层叠样式表&#xff09;或 HTML&#xff08;超文本标记语言&#xff09;代码的新型拖放式网站构建器&#xff0c;为设计师和机…

如何把可观测需求落地为业务大盘?

2022 年 9 月 28 日&#xff0c;阿里云用户组&#xff08;AUG&#xff09;第 11 期活动在深圳举办。活动现场&#xff0c;阿里云技术专家李加贝向参会企业代表分享了如何把可观测需求落地为业务大盘的议题。本文根据现场分享内容整理而成。 为什么需要 Grafana&#xff1f; 演…

智能合约Smart Contract技术详解

文章目录合约编写基本介绍构造方法ipfsmint提现白名单合约前端部署验证合约代码前端和合约交互准备工作获取已经mint了的数量mint合约编写 建议读者先了解下solidity&#xff0c;这里推荐CryptoZombies&#xff0c;还是比较详细的。 ok当你大概知道自己在做什么之后&#xff0…

【概率论】期末复习笔记:假设检验

假设检验目录一、假设检验的基本概念1. 假设检验的基本原理2. 两类错误3. 假设检验的一般步骤4. ppp值二、正态总体参数的假设检验σ2已知&#xff0c;检验μ与μ0的关系\color{dodgerblue}\sigma^2\text{已知&#xff0c;检验}\mu\text{与}\mu_0\text{的关系}σ2已知&#xff…

上海华清远见

解析设备树节点信息实例1获取属性数值实例2获取u32类型的值将获取到的u32类型的值存放在array数组中

什么是许可式邮件营销?

邮件是很多企业日常中用到的信息传播工具&#xff0c;并且它还具备了成本低、长期性等优点&#xff0c;所以很多企业选择使用邮件作为载体进行营销推广。而在进行邮件营销的时候&#xff0c;不同的方式和技巧也会影响到最终的营销效果。为了达到较好的营销效果&#xff0c;很多…

Seata应用

下载seata-server 下载地址&#xff1a;Tags seata/seata GitHub 配置Seata-server 第一步&#xff1a;配置seata-server数据源 E:\seata-server-1.4.2\seata\seata-server-1.4.2\conf\file.conf 第二步&#xff1a;创建seata数据库 create database seata 第三步&#xf…

单元测试-SpringBoot Test和Mock

单元测试-SpringBoot Test和Mock “单元测试” “junit&#xff0c;mock&#xff0c;桩” 1. 什么是单元测试 定义&#xff1a;是指对软件中的最小可测试单元进行检查和验证。 Java里单元指一个方法。单元测试是在软件开发过程中要进行的最低级别的测试活动&#xff0c;软件的…

玻纤效应对skew的影响(三)

玻纤效应对skew的影响&#xff08;一&#xff09;玻纤效应对skew的影响&#xff08;二&#xff09;对内skew对32Gbps NRZ和64Gbps PAM-4的影响这一篇中&#xff0c;玻纤效应造成的对内skew将会加入到32Gbps NRZ和64Gbps PAM-4 SerDes全链路分析中。PCIe 5.0代表32Gbps NRZ&…

C++GUI之wxWidgets(11)-编写应用涉及的类和方法(6)-事件处理(5)

目录自定义事件wxPostEvent()wxQueueEvent()PopEventHandler()Bind()GetEventUserData()Connect()Unbind()定义自己的事件类事件处理程序与虚拟方法自定义事件 wxPostEvent() void wxPostEvent ( wxEvtHandler * dest,const wxEvent & event ) 在GUI应用程序中&am…

云开发项目中如何管理用户和管理授权?

管理用户 在项目中添加用户后&#xff0c;才能为用户授予对应的资产管理权限。支持修改已创建用户的密码和删除用户。 本文中的 用户 是指在云项目下创建的 B 端子账号&#xff0c;可以和资产授权配合使用&#xff0c;管理 B 端设备和资产。这些 B 端用户账号可以在 智慧行业…

IOS开发基础 · SwiftUI · CS193p Lecture1-2

IOS开发Lecture 1TextRoundedRectangleZstackLecture 2HStackstruct整合组件ContentViewstruct 中创建变量var&letSwiftUI刷新重建点击效果ArrayForeachButtonSpacervar整合小组件SF-symbol上下界限制简化ButtonLecture 1 Text import SwiftUIstruct ContentView: View {…

Node.js 中 cookie的验证登录

认识 cookie 在讲cookie的登录验证之前&#xff0c;先来了解一下cookie是什么&#xff1f;cookie本质是存储在浏览器中的一小段文本信息&#xff08;不超过4kb&#xff09;&#xff0c;是由服务器生成发送到浏览器&#xff08;客户端&#xff09;&#xff0c;浏览器将其保存在…

虚拟化技术学习笔记2

1、虚拟机与容器对比&#xff1a; 2、Hypervisor管理工具对比&#xff1a; 3、QEMU&#xff1a; 软件模拟虚拟化、可以模拟多种硬件&#xff0c;包括X86架构处理器、AMD64架构处理器、ARM、SPARC与PowerPC、AIX架构等&#xff0c;效率低、一般用于研究测试场景。QEMU可以模拟一…

偏微分题目的解法

介绍偏微分是考研数学里的小重点&#xff0c;通常在题干中就能很明显看到偏导数。这种题目一般会有两个小题&#xff0c;且第一题往往送分题&#xff0c;通常是求某个复合函数的偏导&#xff0c;直接用复合函数的求导法则即可得到答案。第二题通常是求原函数&#xff0c;一般来…

NVIDIA 在 WeNet 中开源 Noisy Student Training 方案

为了改进 Noisy Student Training 在非目标领域 ASR 上的性能&#xff0c;英伟达提出新型数据筛选方法 LM Filter。其利用不同解码方式的识别文本之间的差异来作为数据筛选条件&#xff0c;是一个完全无监督的筛选过程。在 AIShell-1 上与无数据筛选的基线相比可以有 10.4% 的性…

PYNQ-Z2 开发板

1. 官方手册写的挺全&#xff0c;了解一下PYNQ-Z2 设置指南 https://pynq.readthedocs.io/en/latest/getting_started/pynq_z2_setup.htmlPYNQ-Z2 Reference Manual v1.0 https://www.mouser.com/datasheet/2/744/pynqz2_user_manual_v1_0-1525725.pdfpynq&#xff08;Python O…

单分散PEG之Amino-PEG24-acid;CAS:196936-04-6氨基-二十四聚乙二醇-羧酸

Amino-PEG24-acid氨基-二十四聚乙二醇-羧酸196936-04-6 中文名称&#xff1a;氨基-二十四聚乙二醇-羧酸 英文名称&#xff1a;Amino-PEG24-acid 分子式&#xff1a;C51H103NO26 分子量&#xff1a;1146.35 CAS&#xff1a;196936-04-6 外观&#xff1a;粘稠液体或者固体粉末&a…

数据的存储(3)浮点数的存储

tips 1. 2. 浮点数内存存储方式与整型是截然不同&#xff0c;不可被整型思维带偏了 我用一个例子来理解浮点数在内存当中的表示方法&#xff0c;先上一个十进制浮点数13.5 1. 利用二进制的权重化为二进制浮点数 二进制权重表小数部分如下&#xff1a; 那么13.5&…

Vue好难理解怎么办?

Vue学习笔记分享给你&#xff0c;希望对你有些帮助&#xff0c;另外推荐2个安装 VScode 中的 Vue 插件 Vue 3 Snippets Vue 3 Snippets - Visual Studio Marketplace 这个插件包含了所有的 Vue.js 2 和 Vue.js 3 的 api 对应的代码片段。插件的代码片段如下表格所示&#xff0…