Получение следующего объекта — различия между версиями
| Korektur (обсуждение | вклад)  (→Специализация алгоритма для генерации следующего разбиения на подмножества) | Korektur (обсуждение | вклад)   (→Специализация алгоритма для генерации следующего разбиения на подмножества) | ||
| Строка 71: | Строка 71: | ||
| непересекающихся подмножеств множеств. | непересекающихся подмножеств множеств. | ||
| }} | }} | ||
| − | Например для n = 5 существуют следующие разбиения: | + | Например для <tex>n = 5</tex> существуют следующие разбиения: | 
| <tex> \{1, 2, 3, 4, 5\}</tex> | <tex> \{1, 2, 3, 4, 5\}</tex> | ||
| Строка 81: | Строка 81: | ||
| <tex> \{1\}~\{2\}~\{3\}~\{4\}~\{5\}</tex> | <tex> \{1\}~\{2\}~\{3\}~\{4\}~\{5\}</tex> | ||
| − | и т. д., всего таких разбиений для n = 5 существует 52. | + | и т. д., всего таких разбиений для <tex>n = 5</tex> существует 52. | 
| '''Примечание:''' | '''Примечание:''' | ||
| Строка 95: | Строка 95: | ||
| '''Рассмотрим алгоритм нахождения лексикографически следующего разбиения на подмножества:''' | '''Рассмотрим алгоритм нахождения лексикографически следующего разбиения на подмножества:''' | ||
| − | *Будем хранить подмножества с помощью двумерного массива, например, разбиение {1, 2, 3} {4, 5} будет выглядеть так: | + | *Будем хранить подмножества с помощью двумерного массива, например, разбиение <tex> \{1, 2, 3\}~ \{4, 5\}</tex> будет выглядеть так: | 
| {| class="wikitable" border = 1 | {| class="wikitable" border = 1 | ||
| Строка 109: | Строка 109: | ||
| <code> | <code> | ||
| − |   //  | + |   // sets - матрица содержащая подмножества | 
|   // used - массив в котором мы храним, удаленные элементы |   // used - массив в котором мы храним, удаленные элементы | ||
| − |   for i = n downto 0 | + |   '''for''' i = n '''downto''' 0 | 
| − |       if   | + |       '''if'''  можем добавить в конец подмножества элемент из used | 
| − |           // добавляем | + |           //добавляем | 
| − |           break; | + |           '''break;''' | 
| − |       for j = a[i].size() - 1 downto 0 | + |       '''for''' j = a[i].size() - 1 '''downto''' 0 | 
| − |           if  | + |           '''if''' можем заменить элемент, другим элементом из массива used   | 
|              //заменяем |              //заменяем | ||
| − |              break; | + |              '''break;''' | 
|           used.add(a[i][j]);   //удаляем элемент и добавляем его в массив |           used.add(a[i][j]);   //удаляем элемент и добавляем его в массив | ||
| − | + |   //далее выведем все получившиеся подмножества | |
| + | |||
| </code>   | </code>   | ||
Версия 21:08, 22 декабря 2012
Содержание
Алгоритм
| Определение: | 
| Получение следующего объекта — это нахождение объекта, следующего за данным в лексикографическом порядке. | 
Объект называется следующим за , если и не найдется такого , что .
Отсюда понятен алгоритм:
- Находим суффикс минимальной длины, который можно изменить без изменения префикса текущего объекта
- К оставшейся части дописываем минимальный возможный элемент (чтобы было выполнено правило )
- Дописываем минимальный возможный хвост
По построению получаем, что — минимально возможный.
Специализация алгоритма для генерации следующего битового вектора
- Находим минимальный суффикс, в котором есть 0, его можно увеличить, не меняя оставшейся части
- Вместо 0 записываем 1
- Дописываем минимально возможный хвост из нулей
for i = n downto 1
    if a[i] == 0
        a[i] = 1
        for j = i + 1 to n
            a[j] = 0
        break
Пример работы
| 0 | 1 | 0 | 1 | 1 | исходный битовый вектор | 
| ^ | находим элемент 0 (самый правый) | ||||
| 0 | 1 | 1 | 1 | 1 | меняем его на 1 | 
| 0 | 1 | 1 | 0 | 0 | меняем элементы правее на нули | 
| 0 | 1 | 1 | 0 | 0 | следующий битовый вектор | 
Специализация алгоритма для генерации следующей перестановки
- Двигаясь справа налево, находим элаемент, нарушающий убывающую последовательность (в обычном порядке, слева направо, см. пример)
- Меняем его с минимальным элементом, большим нашего, стоящим правее
- Перевернем правую часть
for i = n - 1 downto 1
    if a[i] < a[i + 1]
        // a[j] = min {a[j] > a[i], где j > i}
        swap(a[i], a[j])
        reverse(a[i + 1] .. a[n])
        break
Пример работы
| 1 | 3 | 2 | 5 | 4 | исходная перестановка | 
| ^ | находим элемент, нарушающий убывающую последовательность | ||||
| ^ | минимальный элемент больше нашего | ||||
| 1 | 3 | 4 | 5 | 2 | меняем их местами | 
| 1 | 3 | 4 | 2 | 5 | разворачивам правую часть | 
| 1 | 3 | 4 | 2 | 5 | следующая перестановка | 
Специализация алгоритма для генерации следующего разбиения на подмножества
Рассмотрим множество первых n натуральных чисел:
| Определение: | 
| Разбиением на множества называется представление множества, как объединения одного или более, попарно непересекающихся подмножеств множеств. | 
Например для существуют следующие разбиения:
и т. д., всего таких разбиений для существует 52.
Примечание: и - одно и то же разбиение на подмножества.
Упорядочим все разбиения на множества Nn лексикографически. Для этого во-первых в каждом разбиении упорядочим множества лексикографически. Будем говорить, что подмножество лексикографически меньше подмножества , если верно одно из следующих условий:
- существует i такое, что , , для всех j < i: если и только если , и существует k > i такое что ;
- и i < j для всех и \ .
Разбиения упорядочены лексикографически следующим образом. Разбиение лексикографически меньше разбиения если существует такое , что .
Рассмотрим алгоритм нахождения лексикографически следующего разбиения на подмножества:
- Будем хранить подмножества с помощью двумерного массива, например, разбиение будет выглядеть так:
| 1 | 2 | 3 | 
| 4 | 5 | 
-  Двигаясь снизу вверх и справа налево, будем удалять элементы, записывая их в отдельный массив. Будем повторять эту операцию, пока не выполнится одно из условий ниже:
- Каждый раз, рассматривая новый элемент, будем пытаться заменить его уже удаленным элементом из нашего массива, так, чтобы не нарушалась возрастающая последовательность элементов в этом подмножестве. Из всех подходящих элементов выбираем минимальный. Важное замечание: мы не можем заменить 1ый элемент подмножества, мы можем только удалить его.
- Каждый раз, переходя в новое подмножество, будем пытаться дополнить его элементом из уже удаленных, так, чтобы не нарушалась возрастающая последовательность элементов в этом подмножестве. Из всех подходящих элементов выбираем минимальный.
 
- Допишем лексикографически минимальный хвост подмножеств из оставшихся элементов.
// sets - матрица содержащая подмножества
// used - массив в котором мы храним, удаленные элементы
for i = n downto 0
    if  можем добавить в конец подмножества элемент из used
        //добавляем
        break;
    for j = a[i].size() - 1 downto 0
        if можем заменить элемент, другим элементом из массива used 
           //заменяем
           break;
        used.add(a[i][j]);   //удаляем элемент и добавляем его в массив
//далее выведем все получившиеся подмножества
Пример работы
Рассмотрим следующее разбиение:
| 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 | 
