Я создаю библиотеку С++, которая включает класс разделов. Я пытаюсь реализовать сопряжение (объяснено ниже) на месте, и я не могу заставить его работать.
Мои члены класса:
size_t _size;
size_t _length;
std::vector<int> _parts;
В качестве примера целочисленное разбиение [5,4,4,1]
имеет
_size = 14 // 5 + 4 + 4 + 1
_length = 4 // 4 nonzero parts
_parts[0] = 5
_parts[1] = 4
_parts[2] = 4
_parts[3] = 1
_parts[i] = junk // i>3
Если раздел [m_1,m_2,...,m_k]
, то сопряженное с ним [n_1,n_2,...,n_l]
, где
l = m_1 // length and the first part are switched
n_i = sum{ m_j | m_j > i}
Например, сопряжение [5,4,4,1]
составляет [4,3,3,3,1]
. Другой способ увидеть это - выделить раздел как строки единичных квадратов, где число квадратов в i
-й строке равно m_i
. Чтение высот столбцов дает сопряженное. В этом же примере изображение
1| x
4| x x x x
4| x x x x
5| x x x x x
__________
4 3 3 3 1
Математика переведена в синтаксис программирования как m_i = _parts[i-1]
и k = _length
. Здесь сломанная реализация для сопряжения:
void
Partition::conjugate() {
size_t k = _length;
_length = _parts[0];
int newPart;
for (int i=(int)_length; i>0; --i) {
newPart = 0;
for (int j=0; j<k; ++j) {
if (_parts[j] >= i) newPart++;
else break;
}
_parts[i-1] = newPart;
}
}
Это работает много времени, но иногда он перезаписывает часть раздела, которая по-прежнему необходима. Я ищу умный способ сделать сопряжение на месте, т.е. Без создания нового экземпляра Partition
.
Еще один способ думать о сопряжении состоит в том, чтобы понять, что сопряжение является следующей последовательностью
k...k (k-1)...(k-1) ... 1...1
x m_k x(m_(k-1)-m_k) x(m_1 - m_2)
Используя эту идею, у меня есть следующая реализация, которая дает правильный ответ:
void
Partition::conjugate() {
if (_length == _size) {
this->first();
return;
} else if (_length == 1) {
this->last();
return;
}
std::vector<int> diffs;
diffs.push_back(_parts[_length-1]);
for (size_t i=_length-1; i>0; --i)
diffs.push_back(_parts[i-1]-_parts[i]);
size_t pos = 0;
for (int i=0; i<_length; ++i) {
for (int j = diffs[i]; j>0; --j)
_parts[pos++] = (int)_length - i;
}
_length = pos;
}
Однако он использует другой std-вектор, который я пытаюсь избежать.
В соответствии с ответом Евгения Клюева (принятым ниже), здесь приведен последний код, который работает (см. его ответ для деталей):
void
Partition::conjugate() {
if (_length == _size) {
this->first();
return;
} else if (_length == 1) {
this->last();
return;
}
int last = _parts[_length-1];
for (int i=1; i<_length; ++i)
_parts[_size-i] = _parts[i-1] - _parts[i];
size_t pos = 0;
for (int i=0; i<last; ++i)
_parts[pos++] = (int)_length;
for (int i=1; i<_length; ++i) {
for (int j = _parts[_size-_length+i]; j>0; --j)
_parts[pos++] = (int)_length - i;
}
_length = pos;
}