Участник:Irdkwmnsb — различия между версиями
Irdkwmnsb (обсуждение | вклад) (submit) |
(нет различий)
|
Версия 20:08, 1 января 2021
Специализация алгоритма для генерации следующего разбиения на подмножества
Рассмотрим множество первых n натуральных чисел:
Упорядочим все разбиения на множества лексикографически. Для этого, во-первых, в каждом разбиении упорядочим множества лексикографически. Будем говорить, что подмножество лексикографически меньше подмножества , если верно одно из следующих условий:
- существует такое, что , , для всех если и только если , и существует такое что ;
- и для всех и \ .
Разбиения упорядочены лексикографически следующим образом. Разбиение лексикографически меньше разбиения если существует такое , что .
Рассмотрим алгоритм нахождения лексикографически следующего разбиения на подмножества:
- Будем хранить подмножества в списке списков, например, разбиение будет выглядеть так:
| 1 | 2 | 3 |
| 4 | 5 |
- Будем поддерживать массив "удалённых" элементов — элементы которые затем нужно будет вернуть в разбиение.
- Двигаясь снизу вверх будем рассматривать подмножества.
- Если мы можем дописать в текущее подмножество минимальный элемент из удалённых, то мы нашли следующее разбиение и идти дальше вверх не нужно.
- Если дописать не можем, значит, либо нужно укоротить и заменить какой то элемент в текущем подмножестве, либо перейти к следующему подмножеству. Будем идти справа налево и рассамтривать элементы:
- Если мы можем заменить текущий элемент минимальным удалённым — мы нашли следующее разбиение, завершаем оба прохода. Стоит отметить, что нельзя перезаписывать последний элемент в подмножестве, иначе мы не сможем дописать минимальный хвост после этого подмножества — в удалённых будет элемент меньше текущего и мы не сможем дописать правильный хвост.
- Если заменить не можем, то его нужно удалить.
- Допишем лексикографически минимальный хвост подмножеств из оставшихся удалённых элементов.
list<list<int>> nextSetPartition(list<list<int>> a):
used = list<int>
// a — список, содержащий подмножества
// used — список, в котором мы храним удаленные элементы
fl = false
for i = a.size - 1 downto 0
if (used.size != 0) and (max(used) > a[i][-1]) // в удалённых есть хотя бы один элемент, который мы можем добавить в конец.
m = минимум из used строго больше a[i][-1]
a[i].add(m) //добавляем
used.remove(m)
break
for j = a[i].size - 1 downto 0
if (used.size != 0) and (j != 0) and (max(used) > a[i][j]) //если можем заменить элемент, другим элементом из списка used и он не последний
m = минимум из used строго больше a[i][-1]
a[i][j] = m //заменяем
used.remove(m)
fl = true
break
else
used.add(a[i][-1])
a[i].pop()
if a[i].size == 0
a.pop()
if fl
break
//далее выведем все удалённые, которые не выбрали
sort(used)
for i = 0 to used.size - 1
a.add(list<int>(used[i])) //добавляем лексикографически минимальных хвост
return a
Пример работы
Рассмотрим следующее разбиение:
| 1 | 2 | 3 |
| 4 | 5 |
1 Шаг:
| 1 | 2 | 3 | |
| 4 | 5 | ||
| ^ | Удалили элемент 5. | ||
| used |
2 Шаг:
| 1 | 2 | 3 | |
| 4 | |||
| ^ | Удалили элемент 4. Так как он является последним в подмножестве, то мы не можем заменить его на другой. | ||
| 5 | used |
3 Шаг:
| 1 | 2 | 3 | 4 | |
| ^ | Дополнили первое подмножество элементом 4 | |||
| 5 | used |
4 Шаг:
| 1 | 2 | 3 | 4 | |
| 5 | Дописали лексикографически минимальный хвост | |||
| used |