2390. Разбиения на слагаемые

 

Перечислите все разбиения натурального числа n на сумму натуральных слагаемых. Разбиения должны удовлетворять следующим условиям:

·        Слагаемые в каждом разбиении упорядочены по невозрастанию.

·        Все разбиения перечислены в лексикографическом порядке.

 

Вход.  Одно натуральное число n (1 ≤ n ≤ 40).

 

Выход. Выведите все допустимые разбиения, каждоев отдельной строке.

 

Пример входа

Пример выхода

4

1 1 1 1

2 1 1

2 2

3 1

4

 

 

РЕШЕНИЕ

комбинаторика

 

Анализ алгоритма

Пусть n = x1 + x2 + … + xk – разбиение числа n на натуральные слагаемые. Исходя из условия задачи, слагаемые любого разбиения должны удовлетворять неравенству:

x1 ³ x2 ³³ xk

Первое слагаемое x1​ может принимать значения от 1 до n, а каждое последующее xi (2 £ i £ k) – значения от 1 до  xi-1.

Рекурсивная суть процедуры генерации разбиений состоит в следующем: если при разбиении числа n в качестве первого слагаемого выбрано x1 (x1 £ n), то далее следует сгенерировать все возможные разбиения числа nx1 на слагаемые, не превышающие x1.

 

Реализация алгоритма

В массиве x будем генерировать разбиения числа n.

 

int x[50];

 

Функция f генерирует разбиения числа n и имеет три аргумента:

·        pos – текущая позиция в массиве x;

·        maxмаксимальное допустимое значение слагаемого, которое может находиться в позиции pos;

·        nтекущее значение числа, которое необходимо разложить.

 

void f(int pos, int max, int n)

{

 

Если значение n стало равным нулю, это означает, что разбиение завершено, и текущее содержимое массива x представляет очередное разбиение. В этом случае выводим массив.

 

  if (n == 0)

  {

    for (int i = 0; i < pos; i++)

      printf("%d ", x[i]);

    printf("\n");

    return;

  }

 

В позиции pos массива x может находиться любое число от 1 до min(max, n).

 

  for (int i = 1; i <= min(max, n); i++)

  {

    x[pos] = i;

    f(pos + 1, i, n - i);

  }

}

 

Основная часть программы. Читаем входное значение n и запускаем функцию генерации всех возможных разбиений этого числа.

 

scanf("%d",&n);

f(0,n,n);