HDU1100——Trees Made to Order以及卡特兰数

news2024/9/27 9:28:19

HDU1100——Trees Made to Order

题目描述

Problem - 1100

运行代码

#include <iostream>
#include <vector>
using namespace std;
vector<long long> C(21, 1);  // 第21个卡特兰数达到65亿
// 预处理卡特兰数
void Catalan() {
    for (int i = 1; i <= 20; i++) {
        C[i] = C[i - 1] * (4 * i - 2) / (i + 1);
    }
}
// 输出n个节点中,排序第rank的二叉树
void PrintfAnswer(int n, long long rank) {
    if (n == 1) {  // 只有1个节点
        cout << "X";
        return;
    }
    if (rank <= C[n - 1]) {  // 排名靠前,即没有根节点没有左子树
        cout << "X";
        cout << "(";
        PrintfAnswer(n - 1, rank);
        cout << ")";
    }
    else if (rank >= C[n] - C[n - 1] + 1) {  // 排名靠后,即没有根节点没有右子树
        cout << "(";
        PrintfAnswer(n - 1, rank - (C[n] - C[n - 1]));
        cout << ")";
        cout << "X";
    }
    else {
        int t = n - 2;
        long long temp;
        long long ExceptLeftAllTree = C[n] - C[n - 1];  // 根节点除了只有左子树外,一共还有的树的种类(包括只有右子树)
        int LeftTreeNum;
        int RightTreeNum;
        long long NewRank;  // 找出的新的种类的树中的排序(求出左右子树数量的  该种类  中的排序)
        for (int i = t; i >= n - 1 - t; i--) {  // i为根节点左子树数量
            temp = C[i] * C[n - 1 - i];  // 例如:若n = 5,则C[3]*C[1](即左子树为3,右子树为1的类型有temp种)
            if (rank > ExceptLeftAllTree - temp) {  // 检测是否符合左子树为i,又右子树为n-1-i
                LeftTreeNum = i;
                break;
            }
            else {
                ExceptLeftAllTree -= temp;
            }
        }
        // 求出左右子树各多少之后,算出在该类型树中的排序NewRank
        NewRank = rank - (ExceptLeftAllTree - temp);
        RightTreeNum = n - LeftTreeNum - 1;

        cout << "(";
        long long LeftTreeRank;  // 左子树中的排序
        // 这个地方需要注意:右子树的优先级是小于左子树的,所以每次判断子数中的排序时,注意左子树每变换一次,右子数变换C[RightTreeNum]次
        if (NewRank < C[RightTreeNum]) {  // 注意排序
            LeftTreeRank = 1;
        }
        else if (NewRank % C[RightTreeNum] == 0) {
            LeftTreeRank = NewRank / C[RightTreeNum];
        }
        else {
            LeftTreeRank = NewRank / C[RightTreeNum] + 1;
        }
        PrintfAnswer(LeftTreeNum, LeftTreeRank);
        cout << ")X(";
        long long RightTreeRank;  // 右子树中的排序
        if (NewRank % C[RightTreeNum] == 0) {
            RightTreeRank = C[RightTreeNum];
        }
        else {
            RightTreeRank = NewRank % C[RightTreeNum];
        }
        PrintfAnswer(RightTreeNum, RightTreeRank);
        cout << ")";
    }
}
int main() {
    Catalan();  // 预处理卡特兰数
    long long n;
    while (cin >> n && n) {
        int i;
        int c;
        for (i = 1;; i++) {
            if (n > C[i]) {
                n -= C[i];  // 求出在当前节点所有排序中的名次
            }
            else {
                c = i;  // 求出当前是i节点组成的二叉树
                break;
            }
        }
        PrintfAnswer(c, n);
        cout << endl;
    }
    return 0;
}

代码思路

  1. Catalan 函数:目的是预先计算并存储卡特兰数。通过一个循环,根据卡特兰数的递推公式计算并填充 C 数组。

  2. PrintfAnswer 函数:

    • 这是核心的递归函数,用于根据给定的节点数 n 和排名 rank 来输出对应的二叉树结构。
    • 对于 n 为 1 的简单情况,直接输出 X 表示单个节点。
    • 当 rank 小于等于前 n - 1 个节点的卡特兰数 C[n - 1] 时,说明根节点没有左子树,先输出 X ,然后递归处理右子树。
    • 当 rank 大于等于从后数第 n - 1 个节点的卡特兰数偏移量时,说明根节点没有右子树,先递归处理左子树,再输出 X 。
    • 对于其他情况,通过循环找到左右子树节点数的组合,计算出新的排名,并分别递归处理左右子树。
  3. main 函数:

    • 首先调用 Catalan 函数进行预处理。
    • 然后在一个循环中,通过不断减去相应节点数的卡特兰数,找到输入的排名 n 所对应的节点数 c 。
    • 最后调用 PrintfAnswer 函数输出对应节点数和排名的二叉树结构。

卡特兰数

卡特兰数(Catalan number)是组合数学中一个常出现于各种计数问题中的数列。

定义与通项公式
递推关系

特点和性质

应用场景
括号化问题

有n对括号,求括号正确配对的字符串数,例如 0 对括号:[空序列] 1 种可能;1 对括号:() 1 种可能;2 对括号:()() (()) 2 种可能 等 。

出栈次序问题

一个栈(无穷大)的进栈序列为1,2,3...,有多少个不同的出栈序列。

凸多边形三角划分

在一个凸多边形中,通过若干条互不相交的对角线,把这个多边形划分成了若干个三角形,求不同划分的方案数。

路径问题
  • 在n×n的网格上,每次只能向右或向上走一格,在不穿越网格主对角线(从左下角到右上角的对角线)的情况下,从左下角走到右上角的不同路径计数。
  • 一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班,如果她从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路 。
二叉树相关

给定n个节点,能构成多少种不同的二叉树 。

#include <iostream>

// 计算卡特兰数
long long catalanNumber(int n) {
    long long catalan[n + 1];
    catalan[0] = catalan[1] = 1;

    for (int i = 2; i <= n; i++) {
        catalan[i] = 0;
        for (int j = 0; j < i; j++) {
            catalan[i] += catalan[j] * catalan[i - j - 1];
        }
    }

    return catalan[n];
}

int main() {
    int n;
    std::cout << "请输入节点数量 n: ";
    std::cin >> n;

    long long numTrees = catalanNumber(n);
    std::cout << "给定 " << n << " 个节点,可以构成 " << numTrees << " 种不同的二叉树。" << std::endl;

    return 0;
}
买票找零问题

有2n个人排成一行进入剧场。入场费 5 元。其中只有n个人有一张 5 元钞票,另外n人只有 10 元钞票,剧院无其它钞票,问有多少种方法使得只要有 10 元的人买票,售票处就有 5 元的钞票找零(将持 5 元者到达视作将 5 元入栈,持 10 元者到达视作使栈中某 5 元出栈)。

#include <iostream>

// 计算卡特兰数的函数
long long catalanNumber(int n) {
    long long dp[n + 1];
    dp[0] = dp[1] = 1;

    for (int i = 2; i <= n; i++) {
        dp[i] = 0;
        for (int j = 0; j < i; j++) {
            dp[i] += dp[j] * dp[i - j - 1];
        }
    }

    return dp[n];
}

// 解决买票找零问题的函数
long long ticketChangeProblem(int n) {
    return catalanNumber(n);
}

int main() {
    int n;
    std::cout << "请输入人数(n): ";
    std::cin >> n;

    long long ways = ticketChangeProblem(n);
    std::cout << "有 " << ways << " 种方法使得只要有 10 元的人买票,售票处就有 5 元的钞票找零。" << std::endl;

    return 0;
}

思路

  1. catalanNumber 函数:

    • 目的是计算卡特兰数。
    • 使用一个动态规划数组 dp 来存储中间结果。
    • 初始化 dp[0] 和 dp[1] 为 1 ,因为卡特兰数的初始情况。
    • 通过两层循环,对于每个 i (大于 1 ),计算 dp[i] 的值。它是通过累加 dp[j] * dp[i - j - 1] (其中 j 从 0 到 i - 1 )得到的,这是基于卡特兰数的递推关系。
  2. ticketChangeProblem 函数:

    • 这个函数直接调用 catalanNumber 函数来计算买票找零问题的结果,因为买票找零问题的方案数就是卡特兰数。
  3. main 函数:

    • 首先提示用户输入人数 n 。
    • 调用 ticketChangeProblem 函数计算方案数,并将结果存储在 ways 变量中。
    • 最后输出结果,即有多少种方法使得只要有 10 元的人买票,售票处就有 5 元的钞票找零。

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

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

相关文章

网络学习:应用层DNS域名解析协议

目录 一、简介 二、工作流程 一、简介 DNS( Domain Name System)是“域名系统”的英文缩写&#xff0c;是一种组织成域层次结构的计算机和网络服务命名系统&#xff0c;它用于TCP/IP网络&#xff0c;它所提供的服务是用来将主机名和域名转换为IP地址的工作。 同时,DNS…

[Leetcode 875][Medium]-爱吃香蕉的珂珂-二分搜索

目录 一、题目描述 二 、整体思路 三 、代码 一、题目描述 原题地址 二 、整体思路 题目要求在时间h内(含h)&#xff0c;求解最小速度k。那么首先要知道速度与吃香蕉所用时间的关系。 假设速度为k&#xff0c;那么吃香蕉所用时间t就等于每堆香蕉piles[i]除以速度k所得的向…

电子元器件—电容和电感(一篇文章搞懂电路中的电容和电感)(笔记)(面试考试必备知识点)电容和电感作用、用途、使用、注意事项、特点等(面试必备)-笔记(详解)

作者&#xff1a;Whappy 座右铭&#xff1a;不曾拥有&#xff0c;何来失去&#xff01; 时间&#xff1a;2024年8月2日08:40:04 一、电容的作用 储能&#xff1a; 电容器通过充电储存电荷在电容板上&#xff0c;形成电场储存电能。当需要释放储存的电能时&#xff0c;电荷…

django集成pytest进行自动化单元测试实战

文章目录 一、引入pytest相关的包二、配置pytest1、将django的配置区分测试环境、开发环境和生产环境2、配置pytest 三、编写测试用例1、业务测试2、接口测试 四、进行测试 在Django项目中集成Pytest进行单元测试可以提高测试的灵活性和效率&#xff0c;相比于Django自带的测试…

回测本身就是一种过度拟合?

这也许是一个絮絮叨叨的专题&#xff0c;跟大伙儿唠一唠量化相关的小问题&#xff0c;有感而发写到哪算哪&#xff0c;这是第一期&#xff0c;先唠个10块钱的~ 前段时间在某乎上看到这样一个问题『您怎么理解回测本身就是一种过度拟合&#xff1f;』 个人看来&#xff0c;回测本…

JavaWeb学习——mybatis

目录 一、入门学习 1、什么是mybatis&#xff1f; 2、入门使用 3、配置SQL提示 4、数据库连接池 5、lombok 二、基础操作学习 1、删除 2、新增 3、更新 4、查询 三、XML配置文件 1、映射规范 2、示例代码展示 四、动态SQL 1、学习 2、学习 3、学习 4、学习 一…

TCP/IP协议:互联网通信的基础

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【深度学习】【框架】【基本结构】激活函数

1. relu 2. softmax 3. sigmoid 4. silu 函数&#xff1a;f(x) x * sigmoid(x) 优点&#xff1a; 它既有 ReLU&#xff08;Rectified Linear Unit&#xff09;激活函数的一些优点&#xff08;例如&#xff0c;能够缓解梯度消失问题&#xff09;&#xff0c;又能解决 ReLU …

JavaEE---Spring MVC(2)

5.传递数组 当请求中参数是多个的时候,浏览器就会封装成一个数组 下面是在postman中返回的值 6.传递集合 运行的时候报错了,状态码是500,表示此时是服务器的错误,我们去查看后端源码发现 默认封装的是数组而不是List接口 修改方式: 此时我们就拿到了列表的值 状态码是HT…

文案生成器有哪些?4款为你一键生成原创文案

大家好&#xff01;今天来分享一波超级实用的干货——文案生成器&#xff01;在今天这个信息爆炸的时代&#xff0c;咱们无论是打理社交媒体&#xff0c;还是搞广告宣传等等&#xff0c;对优质文案的需求那是与日俱增。可有时候&#xff0c;灵感枯竭、时间紧迫&#xff0c;怎么…

测试类型分类

前言&#x1f440;~ 上一章我们介绍了如何设计一个测试用例&#xff0c;接下来我们对测试类型进行分类以便更好的了解和分清不同测试测试的内容、对象、时间点等 按照测试对象划分 界面测试&#xff08;也称UI测试&#xff09; 可靠性测试 容错性测试 文档测试 兼容性测…

vue2怎么上传文件夹,并展示文件夹内的图片?

我使用的是element-ui组件库,发现el-upload组件并不能满足需求,于是用原生实现一下,这里贴一下关键代码,如果大家有更好的实现方法,欢迎分享!! 实现效果:

Jangow-1.0.1靶机

一、安装Jangow: 1.0.1靶机 下载靶机&#xff0c;导入到virtualBox里面 开机可以看到&#xff0c;他已经给出了靶机的IP地址&#xff0c;就不用我们自己去探测了 二、信息收集 扫描靶机的端口 首先访问80端口 扫描目录也就是一个site 点击site&#xff0c;来到以下界面 发现…

进阶SpringBoot之自动装配原理

pom.xml&#xff1a; spring-boot-dependencies -> spring-boot-starter-parent spring-boot-dependencies&#xff1a;核心依赖在父工程&#xff0c;引入依赖时不需要指定版本 启动器&#xff1a;SpringBoot 的启动场景 <dependency><groupId>org.springfra…

机器学习练手(二):基于KMeans的股票分类

总结&#xff1a;本文为和鲸python 可视化探索训练营资料整理而来&#xff0c;加入了自己的理解&#xff08;by GPT4o&#xff09; 原活动链接 在前一关我们学习了逻辑回归&#xff0c;学会如何训练模型、数据基础性分析、如何处理空值等操作&#xff0c;下面我们开始新的一关…

AI+生命科学第二课:入门RNA和特征学习 【Datawhale AI夏令营】

教程链接&#xff1a;Task2&#xff1a;深入理解赛题&#xff0c;入门RNN和特征工程 打卡;https://linklearner.com/activity/12/4/4 在大佬讲解的基础上&#xff0c;带上一些我自己的理解 分析训练流程 从原始特征到输入模型 初始数据转换为tensor后&#xff0c;将x通过fo…

【C++】初识引用

目录 概念引用的五大特性引用在定义时必须初始化一个变量可以有多个引用一个引用可以继续有引用引用了一个实体就不能再引用另一个实体可以对任何类型做引用(包括指针) 引用使用的两种使用场景做参数交换两数单链表头结点的修改 做返回值优化传递返回值 常引用权限放大这时候进…

【前端学习笔记二】CSS基础二

一、颜色模型 1.颜色设置 颜色名称 https://www.w3schools.com/colors/colors_names.asp 这里是一些颜色的名称&#xff08;关键字&#xff09;&#xff0c;比如red、black、green等&#xff0c;可以直接指定名称来设置颜色。名称不区分大小写。 color:red;transparent tr…

OCC 网格化(三)-网格划分算法原理

目录 一、简介 二、基本原理 三、工作流程 四、BRepMesh模块与网格化流程 4.1 BRepMesh 主要组件 4.2 工作流程 4.3 网格生成示例 五、关键参数总结 一、简介 BRepMesh_IncrementalMesh 是一种基于迭代细分的网格划分算法,通过设置线性偏转和角偏转参数,可以生成高精…

利用Python爬虫实现数据收集与挖掘

Python爬虫通常使用requests、selenium等库来发送HTTP请求&#xff0c;获取网页内容&#xff0c;并使用BeautifulSoup、lxml等库来解析网页&#xff0c;提取所需的数据。 以下是一个简单的Python爬虫示例&#xff0c;用于从某个网页上抓取数据&#xff1a; import requests …