- •Анализ алгоритмов (Лекции 2000)
- •Глава 1. Модели вычислений.
- •Глава 3. Перестановки как абстрактный тип данных
- •3.1 Представление перестановок в естественной форме.
- •Var a : array [1..N] of Boolean;
- •Var I, j, k, m:1..N; a:array[1..N] of Boolean;
- •If a[I] then
- •Var I,j:1..N; s:boolean:
- •Var I,j,k:1..N: a:array[1..N] of boolean;
- •If a[I] then
- •3.2 Представление перестановок в циклической форме.
- •Procedure trsl(var f: tpe; var g: tpc);
- •Var I : 1..N; s : Boolean;
- •If a[I] then
- •Procedure u1(var f : tpe; var g : tpk);
- •Var r : real;
- •3.3 Представление перестановок в виде таблицы инверсий.
- •Var I : 0..N; s : Boolean;
- •Var I, j, k : integer;
- •Var c : array [0..N] of 0..1;
- •X : array [1..N] of real;
- •Function ч3 (var r :tpi) : Boolean;
- •Var k, I, j, s, : integer;
- •3.4 Задача о складывании карт.
- •Var I,a,b : integer;
- •Var z:integer;
- •Глава 4. Генерация перестановок
- •4.1Генерация перестановок в лексикографическом порядке.
- •Var р : array [0..N] of 0..N; { текущая перестановка}
- •Var p : array [1..N] of 1..N;
- •Генерация перестановок за минимальное число транспозиций
- •Var I,k : integer;
- •Var p:array [0..N1] of 1..N1;
- •I,j,k,t: integer;
- •Глава 5. Генерация подмножеств множества
- •5.1Генерация подмножеств в лексикографическом порядке.
- •5.2 Генерация подмножеств за счет их минимального изменения.
- •Var s : array [1..N] of 0..1;
- •I : integer;
- •Var s : array [1..N] of 0..1;
- •I,j,k,p : integer;
- •Var t : array [0..N] of 1..N1; {стек}
- •Var t : array [0..N1] of 1..N2;
- •I,p : integer;
- •5.3Генерация мультимножеств.
- •Глава 6. Генерация k-подмножеств
- •Var s : array[1..K] of 1..N;
- •I,p : integer;
- •6.1Генерация k-подмножеств заменой одного элемента.
- •Var I : integer;
- •Var I,m,h:integer;
- •Упражнение. Выполните приведенный алгоритм для деревьв
- •В режиме неполного вычисления
- •Глава 8 Теорема о сложности рекурсивных программ
- •Глава 9 Производящие функции
Глава 6. Генерация k-подмножеств
Подмножество, содержащее к элементов заданного множества А из n элементов (kn), обычно называют K-подмножествами просто K-множествами. Для представления K-подмножеств, наряду с представлением в виде n-последовательностей нулей и единиц, которое обычно применяют только для хранения в упакованном виде, часто используется представление в виде K-кортежей натуральных чисел. При этом каждый кортеж считается упорядоченным, например, в порядке возрастания. Это связано с тем, что чаще kn/2. (Так как K-множество и его дополнение однозначно связаны, и поставленную перед пользователем задачу удается переформулировать, используя либо K-множество, либо его дополнение.) Поэтому при хранении K-множеств в виде n-последовательностей нулей и единиц не менее половины из них являются нулями. При хранении K-кортежами могут, например, указываться порядковые номера элементов, входящих в K-множество.
Пример. Множеству (0,0,0,0,1,1,0,1,1,0,0) соответствует кортеж (5,6,8,9).
Перейдем теперь к алгоритму генерирования K-подмножеств в лексикографическом порядке. Прежде всего дадим определение лексикографической упорядоченности в терминах K-кортежей.
Определение. Множество (а1,...,аk), a1<...<ak, предшествует множеству (b1,...,bk), b1<...<bk, если существует i, 1ik, такое, что для любого j, j<i, aj=bj, ai<bi.
Упражнение. Доказать, что это определение эквивалентно определению лексикографической упорядоченности из п.3.1.
Первым в лексикографическом порядке является кортеж (1,...,k), а последним - (n-k+1,...,n). Пусть (а1,...,аk) не совпадает с последним кортежем генерации, тогда непосредственно следующим за ним является (b1,...,bk) = (а1,...,ap-1,ap+1,ap+2,...,ap+k-p+1), где р=max(i : ai<n-k+1).При этом, если (b1,...,bk) не последний, то следующий за ним выглядит так: (b1,...,br-1,br+1,br+2,...,br+k-r+1), где r=p-1, если bk=n, и k, если bk<n.
Пример. Генерации K- подмножеств в лексикографическом порядке. n=5, k=2.
1.(1,2) 5.(2,3) 8.(3,4) 10.(4,5)
p=2 p=2 p=2
2.(1,3) 6.(2,4) 9.(3,5)
p=2 p=2 p=1
3.(1,4) 7.(2,5)
p=2 p=1
4.(1,5)
p=1
Это приводит к следующему алгоритму на языке Паскаль:
program SUBSET1;
const n= ; k= ; (k<=n)
Var s : array[1..K] of 1..N;
I,p : integer;
begin
for i:=1 to k do
{1} s[i]:=i; {задание первого K-множества}
p:=k;
while p>=1 do
begin
for i:=1 to k do write(s[i]); writeln;
{вывод очередного K-множества}
if s[k]=n then p:=p-1 else p:=k;
if p>=1 then
begin
s[p]:=s[p]+1;
for i:=p+1 to k do
{3} s[i]:=s[i-1]+1
end
end
end.
Оценим вычислительную сложность программы. Заметим, что оператор сроки {1} исполняется k раз; строки {2} - C раз; а строки {3} - C-1+ C-1+....+ C-1 раз, равное C-k-1. То есть вычислительная сложность программы O(C). Учитывая, что C = C[(n+1)/(n-k+1)] и C[k/(n-k+1)], получаем, что алгоритм линеен, за исключением случаев, когда k=n-o(n). В этом случае алгоритм можно применить для порождения (n-k)-подмножеств, с последующим переходом к их дополнению.
Упражнение. Написать вариант программы SUBSET1 для K-подмножеств, представленных n-последовательностями нулей и единиц. Оценить вычислительную сложность построенной программы.