Смысл следующий: берем массив из 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;
}
Комментариев нет:
Отправить комментарий