C программирование чисел и гор - PullRequest
0 голосов
/ 28 сентября 2018

Я создал программу на 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 enter image description here source

Моя цель состояла в том, чтобы иметь возможность создать программу, которая:

  1. как только вы дадите им номер, вы сможете выбрать количество «горных вершин» (<= число) </p>

  2. программа будет подсчитывать, сколько различных горных цепей, (иззаданное число), иметь такое количество горных вершин.

По pdf-файлу я знаю, что:

число n = 3 & "горные вершины" = 2 -> есть 3 (из общего числа 5) горных хребтов с 2 горными вершинами (оба горных "типа").

число n = 4 & "горные вершины" = 3 -> 6 различных горных хребтов.

Мой вопрос: как лучше всего выполнить эту работу?Есть ли формула для этого?Я думал о Паскале Треугольник и серии Фибоначчи, но я не нашел никакой связи между ними.Интересно, что может быть возможным решением.Любая помощь будет по-настоящему признательна.Спасибо.

1 Ответ

0 голосов
/ 28 сентября 2018

Давайте сначала рассмотрим метод грубой силы.

Каталонское число c n - это количество способов, которыми можно комбинировать n ходов вверх(╱) и n нажатий (╲), не опускаясь ниже горизонта.По определению c n = (n + 2) / 2 · (n + 3) / 3 · ... (n + n) /n.

Мы можем использовать беззнаковые 2 n битовые целые числа для описания каждой комбинации.(Однако не все 2 n битовых целочисленных значений без знака описывают действительную комбинацию.) Если мы рассматриваем ненулевой или установленный бит как восходящий удар, а нулевой бит - как нисходящий, пик возникает, когда после нисходящего удара следует заход вверх.(Когда за ходом вниз следует за ходом вверх, у вас есть долина.)

(Обратите внимание, что не все беззнаковые 2 n битовые целочисленные значения описывают действительную комбинацию. Чтобы быть действительным, оченьпервый бит должен быть восходящим, и должно быть точно 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 (01 b в двоичном виде: ход вверх, затем ход вниз, чтение цифр в порядке возрастания значимости, справа налево).В 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;
}

С помощью этих двух функций вы можете решить поставленный вопрос для мелкого n , исследуя все 2 n -битцелые числа без знака (от 0 до (1 << (2*n)) - 1 включительно).


Для лучшего подхода давайте проверим количество пиков для каждого 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 действительных комбинации.Из них один с одним пиком, 15 с двумя пиками, 50 с тремя пиками, 50 с четырьмя пиками и один с шестью пиками.

Если мы просто сформируем целочисленные последовательности для подсчета пиков, мыможно выразить вышеуказанное как

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, мы обнаружим, что это на самом деленазываемые числами Нараяны T ( n , k ), и вся целочисленная последовательность равна OEIS A001263 .

(Примечание: я не знал, что это так! Все, что я знал, я мог использовать OEIS, чтобы узнать, была ли известна последовательность, и обычно они есть. Другими словами, я не просто показываю вам ответ на этот конкретный вопрос здесь., но как я нахожу - весьма эффективно, если можно так выразиться, - решения этой проблемы, начиная с численного подхода грубой силы.)

Таким образом, математический ответ таков: число Нараяны T ( n , k ) сообщает вам количество различных горных цепей, соответствующих каталонскомучисло c n с точными k пиками.

Если вы реализуете биномиальный коэффициент как функцию binomial(n, k),тогда ответ будет T(n, k) = binomial(n, k) * binomial(n, k - 1) / n.

Обратите внимание, однако, что вы можете реализовать T(n, k) более эффективно как разделение между продуктами терминов (то есть, используя два массива терминов и исключая общие термины и продуктычленов, использующих вспомогательную функцию * наибольший общий делитель *, без проблем с точностью из-за отмены термина.)

...