Смысл следующий: берем массив из m элементов и заполняем его случайными числами в диапазоне от 0 до n. Последнему элементу присваиваем значение n. Мы получили массив, в котором содержатся "метки" — значения указывающие на то, в каком именно месте будет разбито наше множество.
Затем сортируем массив, последовательно начиная с m-1-ого элемента находим разность между i-м и i-1-м элементами и записываем её в i-ую ячейку массива. Нулевой элемент массива оставляем без изменений.
Проблема в том, что этот алгоритм не гарантирует, что в результирующем массиве не будут отсутствовать нулевые элементы. С этим можно бороться последующей балансировкой. Заводим специальную переменную (например, diff) для сохранения количества "балансировок" и пока эта переменная не станет равна нулю ходим по массиву и совершаем следующие действия:
- Если наткнулись на ячейку содержащую ноль, прибавляем к её значению единицу, а из переменной единицу вычитаем.
- Если diff меньше нуля, а текущий элемент массива больше нуля, то прибавляем diff единицу, а из текущего элемента её вычитаем.
void getPartition(unsigned n, unsigned m) { if (n < m) { throw out_of_range("N must be greater then M"); } unsigned sum = 0; vector< unsigned > partition; partition.resize(m); // заполнение массива случайными значениями for (unsigned i = 0; i < m; i++) { partition[i] = rand() % n; } partition[partition.size() - 1] = n; // сортировка sort(partition.begin(), partition.end()); // вычитаение for (unsigned i = m - 1; i > 0; i--) { partition[i] = partition[i] - partition[i - 1]; } int diff = 0; // балансировка do { for (unsigned i = 0; i < m; i++) { if (partition[i] < 1) { partition[i]++; diff--; } if (diff < 0) { if (partition[i] > 1) { partition[i]--; diff++; } } } } while (diff != 0); // вывод на экран вместе с суммой всех элементов для проверки for (unsigned i = m - 1; i > 0; i--) { cout << partition[i] << " "; sum += partition[i]; } sum += partition[0]; cout << partition[0] << " " << sum; cout << endl; }
Комментариев нет:
Отправить комментарий