Получение следующего объекта — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Специализация алгоритма для генерации следующего разбиения на подмножества)
(Специализация алгоритма для генерации следующего разбиения на подмножества)
Строка 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>
  // a - матрица содержащая подмножества
+
  // sets - матрица содержащая подмножества
 
  // used - массив в котором мы храним, удаленные элементы
 
  // used - массив в котором мы храним, удаленные элементы
  for i = n downto 0
+
  '''for''' i = n '''downto''' 0
     if  /*можем добавить в конец подмножества элемент из used*/
+
     '''if''' можем добавить в конец подмножества элемент из used
         // добавляем
+
         //добавляем
         break;
+
         '''break;'''
     for j = a[i].size() - 1 downto 0
+
     '''for''' j = a[i].size() - 1 '''downto''' 0
         if /* можем заменить элемент, другим элементом из массива used*/
+
         '''if''' можем заменить элемент, другим элементом из массива used  
 
             //заменяем
 
             //заменяем
             break;
+
             '''break;'''
 
         used.add(a[i][j]);  //удаляем элемент и добавляем его в массив
 
         used.add(a[i][j]);  //удаляем элемент и добавляем его в массив
  printsets();                //далее выведем все получившиеся подмножества
+
  //далее выведем все получившиеся подмножества
 +
 
 
</code>  
 
</code>  
  

Версия 21:08, 22 декабря 2012

Алгоритм

Определение:
Получение следующего объекта — это нахождение объекта, следующего за данным в лексикографическом порядке.

Объект [math]Q[/math] называется следующим за [math]P[/math], если [math]P \lt Q[/math] и не найдется такого [math]R[/math], что [math]P \lt R \lt Q[/math].

Отсюда понятен алгоритм:

  • Находим суффикс минимальной длины, который можно изменить без изменения префикса текущего объекта [math]P[/math]
  • К оставшейся части дописываем минимальный возможный элемент (чтобы было выполнено правило [math]P \lt Q[/math])
  • Дописываем минимальный возможный хвост

По построению получаем, что [math]Q[/math] — минимально возможный.

Специализация алгоритма для генерации следующего битового вектора

  • Находим минимальный суффикс, в котором есть 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 натуральных чисел:[math]N_n = \{1, 2, ..., n\}[/math]


Определение:
Разбиением на множества называется представление множества, как объединения одного или более, попарно непересекающихся подмножеств множеств.

Например для [math]n = 5[/math] существуют следующие разбиения:

[math] \{1, 2, 3, 4, 5\}[/math]

[math] \{1, 2, 3\}~ \{4, 5\}[/math]

[math] \{1, 3, 5\}~ \{2, 4\}[/math]

[math] \{1\}~\{2\}~\{3\}~\{4\}~\{5\}[/math]

и т. д., всего таких разбиений для [math]n = 5[/math] существует 52.

Примечание: [math] \{1, 2, 3\}~ \{4, 5\}[/math] и [math]\{4, 5\} ~\{1, 2, 3, ..., n\}[/math] - одно и то же разбиение на подмножества.

Упорядочим все разбиения на множества Nn лексикографически. Для этого во-первых в каждом разбиении упорядочим множества лексикографически. Будем говорить, что подмножество [math] A \subset N_n [/math] лексикографически меньше подмножества [math] B \subset N_n [/math] , если верно одно из следующих условий:

  • существует i такое, что [math]i \in A[/math] , [math]i \notin A[/math], для всех j < i: [math]j \in A[/math] если и только если [math]j \in B[/math] , и существует k > i такое что [math]k \in B[/math];
  • [math] A \subset B [/math] и i < j для всех [math]i \in A[/math] и [math]j \in B[/math] \ [math] A [/math].

Разбиения упорядочены лексикографически следующим образом. Разбиение [math]N_n = A_1 \cup A_2 \cup . . . \cup A_k[/math] лексикографически меньше разбиения [math]N_n = B_1 \cup B_2 \cup . . . \cup B_l[/math] если существует такое [math]i[/math], что [math]A_1 = B_1, A_2 = B_2, . . . ,A_{i - 1} = B_{i - 1}, A_i \lt B_i[/math].


Рассмотрим алгоритм нахождения лексикографически следующего разбиения на подмножества:

  • Будем хранить подмножества с помощью двумерного массива, например, разбиение [math] \{1, 2, 3\}~ \{4, 5\}[/math] будет выглядеть так:
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

Ссылки