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

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 63: Строка 63:
  
 
== Специализация алгоритма для генерации следующего разбиения на подмножества ==
 
== Специализация алгоритма для генерации следующего разбиения на подмножества ==
 +
{{Определение
 +
|id=def1.
 +
|definition='''Разбиением на множества''' называется представление множества, как объединения одного или более, попарно
 +
непересекающихся подмножеств множеств.
 +
}}
 +
Например для n = 5 существуют следующие разбиения:
 +
 +
'''{1, 2, 3, 4, 5}'''
 +
 +
'''{1, 2, 3} {4, 5}'''
 +
 +
'''{1, 3, 5} {2, 4}'''
 +
 +
'''{1} {2} {3} {4} {5}'''
 +
 +
и т. д., всего таких разбиений для n = 5 существует 52.
 +
 +
'''Примечание:'''
 +
{1, 2, 3} {4, 5} и {4, 5} {1, 2, 3} - одно и то же разбиение на подмножества.
 +
 +
Упорядочим все разбиения на множества Nn лексикографически. Для этого во-первых в каждом разбиении упорядочим множества лексикографически. Будем говорить, что подмножество <tex> A \subset N_n </tex> лексикографически меньше подмножества <tex> B \subset N_n </tex> , если верно одно из следующих условий:
 +
 +
*существует i такое, что <tex>i \in A</tex> , <tex>i \notin A</tex>, для всех j < i: <tex>j \in A</tex> если и только если <tex>j \in B</tex> , и существует k > i такое что <tex>k \in B</tex>;
 +
* <tex> A \subset B </tex> и i < j для всех <tex>i \in A</tex> и <tex>j \in B</tex> \ <tex> A </tex>.
 +
 +
Разбиения упорядочены лексикографически следующим образом. Разбиение <tex>N_n = A_1 \cup A_2 \cup . . . \cup A_k</tex> лексикографически меньше разбиения <tex>N_n = B_1 \cup B_2 \cup . . . \cup B_l</tex> если существует такое <tex>i</tex>, что <tex>A_1 = B_1, A_2 = B_2, . . . ,A_{i - 1} = B_{i - 1}, A_i < B_i</tex>.
 +
 +
 +
'''Рассмотрим алгоритм нахождения лексикографически следующего разбиения на подмножества:'''
 +
*Будем хранить подмножества с помощью двумерного массива, например, разбиение {1, 2, 3} {4, 5} будет выглядеть так:
 +
 +
{| class="wikitable" border = 1
 +
|1||2||3
 +
|-
 +
|4||5||
 +
|}
 +
 
* Двигаясь снизу вверх и справа налево, будем удалять элементы, записывая их в отдельный массив. Будем повторять эту операцию, пока не выполнится одно из условий ниже:
 
* Двигаясь снизу вверх и справа налево, будем удалять элементы, записывая их в отдельный массив. Будем повторять эту операцию, пока не выполнится одно из условий ниже:
 
** Каждый раз, рассматривая новый элемент, будем пытаться заменить его уже удаленным элементом из нашего массива, так, чтобы не нарушалась возрастающая последовательность элементов    в этом подмножестве. Из всех подходящих элементов выбираем минимальный. '''Важное замечание''': мы не можем заменить 1ый элемент подмножества, мы можем только удалить его.
 
** Каждый раз, рассматривая новый элемент, будем пытаться заменить его уже удаленным элементом из нашего массива, так, чтобы не нарушалась возрастающая последовательность элементов    в этом подмножестве. Из всех подходящих элементов выбираем минимальный. '''Важное замечание''': мы не можем заменить 1ый элемент подмножества, мы можем только удалить его.
Строка 71: Строка 108:
 
  // a - матрица содержащая подмножества
 
  // a - матрица содержащая подмножества
 
  // used - массив в котором мы храним, удаленные элементы
 
  // used - массив в котором мы храним, удаленные элементы
  for i = n - 1 downto 0 //перебираем все подмножества, начиная с последнего
+
  for i = n downto 0
     if ( /*можем добавить в конец подмножества элемент из used*/ ){
+
     if /*можем добавить в конец подмножества элемент из used*/  
 
         // добавляем
 
         // добавляем
 
         break;
 
         break;
    }
+
     for j = a[i].size() - 1 downto 0
     for j = m - 1 downto 0 // перебираем все элементы текущего подмножества
+
         if /* можем заменить элемент, другим элементом из массива used*/  
         if( /* можем заменить элемент, другим элементом из массива used*/ ){
 
 
             //заменяем
 
             //заменяем
 
             break;
 
             break;
        }
+
         used.add(a[i][j]);   //удаляем элемент и добавляем его в массив
         used.add(a[i][j]); //удаляем элемент и добавляем его в массив
+
  printsets();                 //далее выведем все получившиеся подмножества
  printsets();               //далее выведем все получившиеся подмножества
+
</code>  
sort(used);                //отсортируем массив оставшихся элементов
 
for i = 0 to used.size() do
 
    println(used[i]);    //выведем лексикографически минимальный хвост
 
</code>
 
  
 
=== Пример работы ===
 
=== Пример работы ===
  
 
'''Рассмотрим следующее разбиение:'''
 
'''Рассмотрим следующее разбиение:'''
{1, 2, 3}
+
 
{4, 5}
+
{| class="wikitable" border = 1
 +
|1||2||3
 +
|-
 +
|4||5||
 +
|}
  
 
'''1 Шаг:'''
 
'''1 Шаг:'''
{1, 2, 3}
 
{4}
 
used = {5};
 
  
Удалили элемент 5.  
+
{| class="wikitable" border = 1
 +
|1||2||3||
 +
|-
 +
|4||style="background:#FFCC00"|5||||
 +
|-
 +
| ||^|| ||Удалили элемент 5.
 +
|-
 +
| || || ||used
 +
|}
 +
 
  
 
'''2 Шаг:'''
 
'''2 Шаг:'''
{1, 2, 3}
 
used = {4, 5};
 
  
Удалили элемент 4. Так как он является первым в подмножестве, то мы не можем заменить его на другой.
+
{| class="wikitable" border = 1
 +
|1||2||3||
 +
|-
 +
|style="background:#FFCC00"|4|| ||||
 +
|-
 +
|^|| || ||Удалили элемент 4. Так как он является первым в подмножестве, то мы не можем заменить его на другой.
 +
|-
 +
|5|| || ||used
 +
|}
 +
 
  
 
'''3 Шаг:'''
 
'''3 Шаг:'''
{1, 2, 3, 4}
 
{5}
 
used = {};           
 
  
Дополнили первое подмножество элементом 4(так как он минимальный из всех элементов, которыми мы могли его дополнить), и дописали лексикографически минимальный хвост.
+
{| class="wikitable" border = 1
 +
|1||2||3||style="background:#FFCC00"|4||
 +
|-
 +
| || || ||^||Дополнили первое подмножество элементом 4
 +
|-
 +
|5|| || || ||used
 +
|} 
 +
 
  
 +
'''4 Шаг:'''
 +
   
 +
{| class="wikitable" border = 1
 +
|1||2||3||4||
 +
|-
 +
|style="background:#FFCC00"|5|| || || ||Дописали лексикографически минимальный хвост
 +
|-
 +
| || || || ||used
 +
|} 
 
== Ссылки ==
 
== Ссылки ==
 
* [[Получение объекта по номеру]]
 
* [[Получение объекта по номеру]]

Версия 19:40, 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 = 5 существуют следующие разбиения:

{1, 2, 3, 4, 5}

{1, 2, 3} {4, 5}

{1, 3, 5} {2, 4}

{1} {2} {3} {4} {5}

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

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

Упорядочим все разбиения на множества 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].


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

  • Будем хранить подмножества с помощью двумерного массива, например, разбиение {1, 2, 3} {4, 5} будет выглядеть так:
1 2 3
4 5
  • Двигаясь снизу вверх и справа налево, будем удалять элементы, записывая их в отдельный массив. Будем повторять эту операцию, пока не выполнится одно из условий ниже:
    • Каждый раз, рассматривая новый элемент, будем пытаться заменить его уже удаленным элементом из нашего массива, так, чтобы не нарушалась возрастающая последовательность элементов в этом подмножестве. Из всех подходящих элементов выбираем минимальный. Важное замечание: мы не можем заменить 1ый элемент подмножества, мы можем только удалить его.
    • Каждый раз, переходя в новое подмножество, будем пытаться дополнить его элементом из уже удаленных, так, чтобы не нарушалась возрастающая последовательность элементов в этом подмножестве. Из всех подходящих элементов выбираем минимальный.
  • Допишем лексикографически минимальный хвост подмножеств из оставшихся элементов.

// a - матрица содержащая подмножества
// 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]);   //удаляем элемент и добавляем его в массив
printsets();                 //далее выведем все получившиеся подмножества

Пример работы

Рассмотрим следующее разбиение:

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

Ссылки