Язык Си в примерах/Треугольник Паскаля

Язык Си в примерах


  1. Компиляция программ
  2. Простейшая программа «Hello World»
  3. Учимся складывать
  4. Максимум
  5. Таблица умножения
  6. ASCII-коды символов
  7. Верхний регистр
  8. Скобочки
  9. Факториал
  10. Степень числа
  11. Корень уравнения
  12. Система счисления
  13. Сортировка
  14. Библиотека complex
  15. Сортировка на основе qsort
  16. RPN-калькулятор
  17. RPN-калькулятор на Bison
  18. Простая грамматика
  19. Задача «Расчёт сопротивления схемы»
  20. Простая реализация конечного автомата
  21. Использование аргументов командной строки
  22. Чтение и печать без использования stdio
  23. Декодирование звукозаписи в формате ADX
  24. Другие примеры
  25. XCC C

Всем известны простые формулы

А как находить коэффициенты в разложении ?

Рассмотрим следующую таблицу:

То, что нарисовано справа, называется треугольником Паскаля — в n-й строчке этого треугольника находятся коэффициенты для разложения .

Число номер в n-й строчке называется биномиальным коэффициентом .

Например,

Стороны треугольника Паскаля состоят из единичек. Каждое число внутри треугольника Паскаля равно сумме двух чисел, стоящих над ним справа и слева в предыдущей строчке:

Эти числа возникают в задаче о числе сочетаний:  — это число способов выбрать k элементов из n различных. Например, число байт, в которых ровно 3 единицы — это число  — число способов выбрать три бита, в которых будут стоять единицы, из восьми бит байта.

Докажите, что

Рассмотрим две программы, которые решают следующие задачи:

  1. Запрограммировать функцию .
  2. Вывести на экран n строчек треугольника Паскаля.
/*
   Вычисление биномиальных коэффициентов.
 */
#include <stdio.h>

long
C (long n, long k)
{
  if (k == 0 || n == k)
    return 1;
  return C (n - 1, k - 1) + C (n - 1, k);
}

int
main ()
{
  long n, k;
  scanf ("%ld%ld", &n, &k);
  printf ("%ld ", C (n, k));
  return 0;
}
  • Сколько раз вызовется функция C(., .) при вычислении С(n, k)?
  • Докажите, что время вычисления по приведенному алгоритму пропорционально .
  • Оцените ассимптотику , а именно, напишите программу, которая вычисляет для и нарисуйте график

от .

/*
    Вычисление n-й строки треугольника Паскаля.
*/
#include <stdio.h>
#define N 1000

int
main ()
{
  long c[N];
  long n, i, j;
  scanf ("%ld", &n);
  for (i = 1; i <= n; i++)
    c[i] = 0;
  c[0] = 1;
  for (j = 1; j <= n; j++)
    for (i = j; i >= 1; i--)
      c[i] = c[i - 1] + c[i];
  for (i = 0; i <= n; i++)
    printf ("%ld ", c[i]);
  return 0;
}
  • Докажите, что указанный алгоритм вычисления n-й строчки треугольника Паскаля

работает быстрее, чем алгоритм вычисления из предыдущей программы, а именно время работы пропорционально .

  • Начиная с какого n самое большое число из n-й строчки треугольника Паскаля не умещается в тип long?

Еще один вариант реализации вычисления Биномиального коэффициента из общей формулы (без рекурсии):

/*
  Вычисление биномиальных коэффициентов
*/
#include <assert.h>
#include <stdio.h>

int
binomial (int row, int pos)
{
  int koef = 1;
  int i;
  for (i = pos + 1; i <= row; i++)
    koef = koef * i;
  for (i = 1; i < (row - pos + 1); i++)
    koef = koef / i;
  return koef;
}

int
main (void)
{
  int row, pos;
  int r = scanf ("%i%i", &row, &pos);
  assert (r == 2);
  printf ("%i", binomial (row, pos));
  return 0;
}

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

/*
  Вычисление биномиальных коэффициентов
*/
#include <assert.h>
#include <stdio.h>

int
binomial (int row, int pos)
{
  int koef = 1;
  int i;
  if (row - pos > pos)
    pos = row - pos;
  for (i = pos + 1; i <= row; i++)
    koef = koef * i;
  for (i = 1; i < (row - pos + 1); i++)
    koef = koef / i;
  return koef;
}

int
main (void)
{
  int row, pos;
  int r = scanf ("%i%i", &row, &pos);
  assert (r == 2);
  printf ("%i", binomial (row, pos));
  return 0;
}

Стоит учитывать, что в реализованных примерах нет защиты от дурака (переполнение значения переменной).