我创建了一个C程序,它给出了第N个加泰罗尼亚数字,到目前为止一切正常。这里是:

#include <stdio.h>

int catalan(int);

main()
{
    int number, catalannumber;

    printf("This is a program to find a given catalan number.\nIntroduce your desired number: ");
    scanf("%d", &number);

    while (number < 1)
    {
        printf("Number must be greater or equal to 1. Reintroduce: ");
        scanf("%d", &number);
    }

    catalannumber = catalan (number);

    printf("The %dth number corresponds to %d.\n", number, catalannumber);
}

int catalan(int n) {
  if (n == 1)
    return 1;
  else
    return 2 * (2*n - 1) * catalan(n-1) / (n+1);
}

然后我发现了这个“经典”的山脉问题,所有可能的山脉如图所示:
http://www.maths.usyd.edu.au/u/kooc/catalan/cat3moun.pdf
以下是“山脉”的小值n
c - C编程数字和山脉-LMLPHP
source
我的目标是能够创建一个程序:
一旦你给了他们号码,你就可以选择“山顶”的号码(这个程序会计算出有多少不同的山脉(在给定的数字中)有那么多的山顶。
根据pdf文件,我知道:
数字n=3&“山顶”=2->有3个(共5个)山脉有2个山顶(两个不同的山“类型”)。
数字n=4&“山顶”=3->6个不同的山脉。
我的问题是,做这项工作的最好方法是什么?有什么公式吗?我考虑过帕斯卡三角和斐波那契级数,但没有发现它们之间的任何关系。我想知道什么是可能的解决办法。
任何帮助都将得到真正的补偿。谢谢。

最佳答案

让我们先来看看暴力手段。
加泰罗尼亚数字cn是一个人可以组合n次上击(╱)和n次下击(╲)而不低于地平线的方式。根据定义,cn=(n+2)/2·(n+3)/3·。。。(n+n)/n。
我们可以使用无符号2n位整数来描述每个组合。(然而,并不是所有的2n位无符号整数值都描述了一个有效的组合。)如果我们将非零位或设置位视为上行程,而将零位视为下行程,则每当下行程跟随上行程时,都会出现峰值。(当下击之后是上击,你就有了一个山谷。)
(请注意,并非所有无符号2n位整数值都描述有效组合。为了有效,第一个位必须是一个上击,并且必须正好有n个上击。)
因此,首先编写一个函数,计算一个组合中由无符号整数描述的峰值数。(请注意,因为描述组合的每个无符号整数正好有n个位集,所以我们不需要显式传递n,只需要传递描述组合的无符号整数即可。)例如,

unsigned int  peaks(unsigned int  description)
{
    unsigned int  count = 0;

    while (description) {
        count += ((description & 3) == 1);
        description >>= 1;
    }

    return count;
}

上面,从最低有效位开始读取组合。(因为它必须设置为山脉可能在地平线以上,所以没有偶数值描述组合。)表达式(description & 3)隔离了最后两个有效位。这四种可能的情况分别对应于双下坡、峰、谷和双上坡,以增加数值。峰值情况对应于值1(二进制为01b:上行程后下行程,从右向左按显著性递增顺序读取数字)。在C中,逻辑False的值为零,逻辑True的值为1,因此在上面的循环中,我们得到一个设置位后面(在更重要的位置)跟一个清晰位的情况数。
Value  Mountains       n   Peaks
    1   ╱╲             1     1
    3   ╱╱╲╲           2     1
    5   ╱╲╱╲           2     2
    7   ╱╱╱╲╲╲         3     1
    9   ╱╲╲╱         Not a valid combination
   11   ╱╱╲╱╲╲         3     2
   13   ╱╲╱╱╲╲         3     2
   15   ╱╱╱╱╲╲╲╲       4     1
   17   ╱╲╲╲╱        Not a valid combination
   19   ╱╱╲╲╱╲         3     2
   21   ╱╲╱╲╱╲         3     3
   23   ╱╱╱╲╱╲╲╲       4     2
   25   ╱╲╲╱╱╲       Not a valid combination
   27   ╱╱╲╱╱╲╲╲       4     2
   29   ╱╲╱╱╱╲╲╲       4     2
   31   ╱╱╱╱╱╲╲╲╲╲     5     1
   33   ╱╲╲╲╲╱       Not a valid combination
   35   ╱╱╲╲╲╱       Not a valid combination
   37   ╱╲╱╲╲╱       Not a valid combination
   39   ╱╱╱╲╲╱╲╲       4     2

接下来,创建一个函数,该函数生成描述特定n的有效组合的所有无符号整数值,并计算对应于特定数量峰值的值。
一种暴力的方法是编写峰值计数函数,以便对于所有无效的组合返回0。例如:
static unsigned int  peaks(unsigned int  description)
{
    unsigned int  count = 0;
    int           height = 0;

    /* Description must start with an upstroke. */
    if (!(description & 1))
        return 0;

    while (description) {
        switch (description & 3) {
        case 0: /* Downslope; next is downslope. */
            if (--height < 0)
                return 0;
            break;

        case 1: /* Upslope; next is downslope. */
            count++;
            height++;
            break;

        case 2: /* Downslope; next is upslope. */
            if (--height < 0)
                return 0;
            break;

        default: /* 3: Upslope; next is upslope. */
            height++;

        }

        description >>= 1;
    }

    return count;
}

描述对应的n(如果peak(description) > 0)是描述中设置的位数。数数的妙招那就是
unsigned int  popcount(unsigned int  value)
{
    unsigned int  count = 0;
    while (value) {
        value &= value - 1;
        count++;
    }
    return count;
}

有了这两个函数,您可以通过探索所有2n位无符号整数(从0(1 << (2*n)) - 1,包括)来解决小n的指定问题。
为了获得更好的方法,让我们检查每个n的峰值数:
n Combs   Occurrences*Peaks
0    1     1*0
1    1     1*1
2    2     1*1,  1*2
3    5     1*1,  3*2,  1*3
4   14     1*1,  6*2,  6*3,  1*4
5   42     1*1, 10*2, 20*3, 10*4,  1*5
6  132     1*1, 15*2, 50*3, 50*4, 15*5, 1*6

换句话说,n=6有132个有效组合。其中,一峰一峰、二峰十五峰、三峰五十峰、四峰五十峰、六峰一峰。
如果我们只是形成峰值计数的整数序列,我们可以表示为
1,
1, 1,
1, 3, 1
1, 6, 6, 1,
1, 10, 20, 10, 1,
1, 15, 50, 50, 15, 1,

以此类推,继续1,21,105,175,105,21,1表示n=7,继续1,28,196,490,490,196,28,1表示n=8,依此类推。
如果我们对这个序列进行OEIS搜索,我们会发现它们实际上被称为Narayana数T(n,k),整个整数序列是OEIS A001263
(注:我不知道是这样!我只知道我可以使用OEIS来确定序列是否已知,而且它们通常是已知的。换言之,我不仅仅是在这里向您展示这个问题的答案,而是如何找到——如果我可以自己这么说的话——这类问题的解决方案,从一种暴力的数值方法开始。)
因此,数学上的答案是,Narayana numberT(n,k)告诉你对应于加泰罗尼亚数cn的不同山脉的数目,正好有k个山峰。
如果将binomial coefficient作为函数binomial(n, k)实现,那么答案是T(n, k) = binomial(n, k) * binomial(n, k - 1) / n
但是,请注意,您可以更有效地实现T(n, k)作为术语乘积的划分(即,使用两个术语数组,并使用greatest common divisor助手函数消除常用术语和术语乘积,而不会由于术语取消而导致精度问题)

关于c - C编程数字和山脉,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52545884/

10-16 07:30