Top.Mail.Ru
Ответы
Аватар пользователя
7 месяцев назад
от

Помогите пожалуйста с++

Перечислите все разбиения целого положительного числа N на целые положительные слагаемые. Разбиения должны обладать следующими свойствами: • Слагаемые в разбиениях идут в невозрастающем порядке. • Разбиения перечисляются в лексикографическом порядке. Входные данные 4
Результат работы
1 1 1 1
2 1 1
2 2
3 1
4

Только авторизированные пользователи могут оставлять свои ответы
Дата
Популярность
Аватар пользователя
Новичок
7мес
12345678910111213141516171819202122232425262728
 #include <iostream>
#include <vector>

using namespace std;

void f(vector<int> &t, int n, int end) {
  if (n == 0) {
    for (auto v: t) { cout << v << ' '; }
    cout << '\n';
    return;
  }

  int pos = t.size();
  t.resize(pos + 1);
  end = min(end, n);
  for (t[pos] = 1; t[pos] <= end; ++t[pos]) {
    f(t, n - t[pos], t[pos]);
  }
  t.resize(pos);
}

int main() {
  int n;
  cin >> n;
  vector<int> t;
  t.reserve(n);
  f(t, n, n);
} 
Аватар пользователя
Мыслитель
7мес

Можно использовать рекурсивный алгоритм.

Подход:
1) Используем рекурсивную функцию для построения разбиений.
Невозрастающий порядок: Каждый следующий слагаемый должен быть меньше или равен предыдущему.
2) Для обеспечения лексикографического порядка будем перебирать первые элементы от 1 до N.
Алгоритм:

Начинаем с пустого разбиения, остатка суммы равного N, и максимального возможного слагаемого, равного N.
Если остаток суммы равен 0, выводим текущее разбиение.
Иначе, для каждого возможного слагаемого от 1 до минимального из текущего остатка суммы и предыдущего слагаемого:
1) Добавляем слагаемое в текущее разбиение.
2) Рекурсивно вызываем функцию с обновленным остатком суммы и текущим слагаемым как новым предыдущим слагаемым.
3) Удаляем слагаемое из текущего разбиения (backtracking).

В итоге разбиения выводятся в процессе рекурсивных вызовов, обеспечивая требуемый порядок

Реализация на c++:

12345678910111213141516171819202122232425262728
 #include <iostream> 
#include <vector> 
 
using namespace std; 
 
void partition(int remaining_sum, int last_element, vector<int>& partition_so_far) { 
    if (remaining_sum == 0) { 
        for (size_t i = 0; i < partition_so_far.size(); ++i) { 
            cout << partition_so_far[i]; 
            if (i + 1 < partition_so_far.size()) cout << " "; 
        } 
        cout << endl; 
        return; 
    } 
    for (int first_element = 1; first_element <= min(remaining_sum, last_element); ++first_element) { 
        partition_so_far.push_back(first_element); 
        partition(remaining_sum - first_element, first_element, partition_so_far); 
        partition_so_far.pop_back(); 
    } 
} 
 
int main() { 
    int N; 
    cin >> N; 
    vector<int> partition_so_far; 
    partition(N, N, partition_so_far); 
    return 0; 
} 
Аватар пользователя
7мес

Перечислить все разбиения целого положительного числа N на целые положительные слагаемые с указанными свойствами можно с помощью онлайн-калькулятора на сайте planetcalc.ru. Он выводит все представления числа n в виде суммы положительных целых чисел, при этом слагаемые перечисляются в невозрастающем порядке. 3

Также для решения этой задачи можно использовать рекурсивный алгоритм, например, как тот, что приведён на сайте cyberforum.ru. 2

Пример разбиений для числа 4: 1+1+1+1, 2+1+1, 2+2, 3+1, 4. 15

Важно учитывать, что число разбиений экспоненциально зависит от числа n.