русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Writeln


Дата добавления: 2013-12-23; просмотров: 878; Нарушение авторских прав


Глава 6. ГЕНЕРАЦИЯ K-ПОДМНОЖЕСТВ

Подмножество, содержащее к элементов заданного множества А из n элементов (k£n), обычно называют K-подмножествами просто K-множествами. Для представления K-подмножеств, наряду с представлением в виде n-последовательностей нулей и единиц, которое обычно применяют только для хранения в упакованном виде, часто используется представление в виде K-кортежей натуральных чисел. При этом каждый кортеж считается упорядоченным, например, в порядке возрастания. Это связано с тем, что чаще k£n/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, 1£i£k, такое, что для любого 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:=1;

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-последовательностями нулей и единиц. Оценить вычислительную сложность построенной программы.

 

6.1Генерация K-подмножеств заменой одного элемента.

Для того чтобы убедиться в том, что подобные генерации существуют, рассмотрим некоторые свойства симметрично-отраженных кодов Грея.

Обозначение. Пусть a-некоторая цепочка над алфавитом Х. Тогда am, где m - целое неотрицательное число, обозначает конкатенацию m раз цепочки a.

Пример. Х={a,b,c} (ab)3=ababab ab3=abbb.

В дальнейшем симметрично-отраженный код Грея n-го порядка, генерируемый программой SET2, будем обозначать G(n). Естественно, что любое кодовое слово из G(n) является цепочкой длины n над {0,1}. Последовательности кодовых слов из G(n), содержащие k единиц и упорядоченные соответственно с их генерацией программой SET2, будем обозначать G(n,k). Последовательности, в которых кодовые слова располагаются в обратном порядке по отношению к G(n) или G(n,k), будем обозначать GR(n) и GR(n,k) соответственно.

Теорема 4.1. Первым кодовым словом в G(n) ровно k единицами будет 1k0n-k, а последним - 1k-10n-k1 и 0n, если k=0.

Доказательство проводится индукцией по n, при n=1 - очевидно. Пусть теорема справедлива для i£n и любых k, покажем, что теорема справедлива для n+1 и всех k. В терминах G(n) соотношение {1} из п.3.2 может быть записано как G(n+1)=G(n)0;GR(n)1, поэтому первое кодовое слово с k³0 единицами (кроме k=n+1) есть первое кодовое слово в G(n) с приписанным справа нулем. Иными словами, 1k0n+1-k, как и требовалось. Аналогично последнее кодовое слово с k³1 единицами в G(n) c приписанной справа единицей - это 1k-10n-k+11, как и требовалось. В случае k=n+1 единственным словом в G(n+1), содержащим n+1 единицу, является 1n+1.

Теорема 4.2. Соседние кодовые слова в G(n,k) различаются ровно в двух разрядах.

Доказательство проводится индукцией по n. Теорема, очевидно, справедлива для n=1, поскольку k=0, либо k=1. Предположим, что теорема верна для n и всех k, 0£k£n. Покажем, что она верна для n+1 и любого k, 0£k£n+1. Если k=0 или k=n+1, она справедлива, так как G(n+1) содержит только одно соответствующее кодовое слово. Для 1£k£n теорема выполняется по индукционному предположению, если кодовые слова оба либо в G(n)0 либо GR(n)1. Таким образом, требуется только рассмотреть, на сколько разрядов отличается последнее кодовое слово с k единицами в G(n)0 от первого кодового слова с k единицами в GR(n)1. Из предыдущей теоремы следует, что эти слова имеют вид: при k=1 0n-110 и 0n1, при k>1 1k-210n-k10 и 1k-200n-k11 соответственно.

Следствие. Последовательность кодовых слов G(n,k), n³k³0, можно определить следующей рекурсией:

G(n,k)=G(n-1,k); GR(n-1,k-1)1 и G(n,0)=0n, G(n,n)=1n. {2}

В самом деле, это определение действительно задает последовательность, совпадающую с той, которая получается удалением из G(n) всех кодовых слов с числом единиц, не равным k.

Рекурсивное определение {2} приводит к следующей программе генерации кодовых слов G(n,k) на языке Паскаль.

program subset2;

const n= ; k= ; {0<k<=n}

var i : integer;

s:array[1..n] of 0..1;

procedure print (m,h:integer);

begin

if h<>0 then h:=1;

for i:=1 to m do s[i]:=h;

for i:=1 to n do write(s[i]);

end;

procedure GR(m,h:integer); forward;

procedure G(m,h:integer);

begin

if (h=0) or (m=h) then print(m,h)

else

begin s[m]:=0; G(m-1,h);

s[m]:=1; GR(m-1,h-1)

end

end;

procedure GR;

begin

if (h=0) or (m=h) then print(m,h)

else

begin s[m]:=1; G(m-1,h-1);

s[m]:=0; GR(m-1,h)

end

end;

begin {SUBSET2} G(n,k) end.

Комментарий. Процедура GR(m,h) соответствует GR(m,h). Процедура print служит для вывода генерируемых кодовых слов.

Для дальнейшего анализа алгоритма остановимся подробнее на дереве вызова процедурG и GR.

 

Пример. n=5, k=3.

G(5,3)

0 1

G(4,3) GR(4,2)

0 1 1 0

G(3,3) GR(3,2) G(3,1) GR(3,2)

1 0 0 1 1 0

G(2,1) GR(2,2) G(2,1) GR(2,0) G(2,1) GR(2,2)

0 1 0 1 0 1

G(1,1) GR(1,0) G(1,1) GR(1,0) G(1,1) GR(1,0)

 

11100 10110 01110 11010 10011 01011 00111 10101 01101 11001

 

Из текста программы видно, что рекурсивная структура G(n,k) представляется в виде бинарного дерева. Каждую дугу, ведущую в G(m-1,h) или GR(m-1,h), пометим значением, которое присваивается s[m] перед вызовом этой процедуры. Обозначать мы будем соответственно G(m-1,h)s[m] или GR(m-1,h)s[m]. Каждое кодовое слово может быть составлено из значения, вырабатываемого листом, и пометок дуг, составляющих ветвь от этого листа к корню дерева. Очевидно, что два соседних кодовых слова в G(n,k) могут отличаться только в тех разрядах, которые соответствуют несовпадающим частях их ветвей. Каждая вершина бинарного дерева характеризуется ее уровнем-значением m. При этом является однозначно определенной часть текущего кодового слова - позиции s[m],...,s[n]. Кроме того, число h определяет количество единиц, находящиеся в позициях s[1],...,s[m-1].

 

Упражнения. 1. Доказать, что листья дерева могут быть помечены (m¹0) G(m,0)1, GR(m,0)1 или G(m,m)0, GR(m,m)0, но не могут с G(m,0)0, GR(m,0)0 или с G(m,m)1, GR(m,m)1.

2. Определить число вызовов процедур G и GR как функцию от n и k. (Указание. Определить число кодовых слов, начало которых состоит из 1,2,...,k единиц, и число слов, начало которых состоит из 1,2,...,n-k нулей.)

3. Определить вычислительную сложность программы SUBSET2.

4. Доказать корректность приведенной программы.

Перейдем к построению итеративного алгоритма генерирования G(n,k). Такой алгоритм должен итеративно моделировать левосторонний[2] обход дерева вызова процедур G и GR. В этом случае моделирование осуществляется за счет перехода от текущего кодового слова к следующему за счет информации о еще не полностью обработанных узлов дерева вызова, лежащих на ветви от листа, соответствующему текущему кодовому слову, до корня дерева - вершины G(n,k). Естественно, информация о таких узлах храниться в стеке обхода дерева. Рассмотрим какую информацию необходимо хранить о каждом из таких узлов в стеке. Прежде всего заметим, что по свойству программы SUBSET2, для каждого узла дерева обхода левой его ветви может соответствовать только вызов процедуры G, а правой - вызов процедуры GR. Поэтому еще не полностью обработанными являются узлы соответствующие вызову процедуры G. Для каждого такого узла в стеке достаточно хранить значение его уровня - m. Так как мы знаем, что последующая обработка этого узла будет связана с преобразованием части кодового слова - разряды s[1],...,s[m], при этом значение h легко вычисляется как число единиц, расположенных в разрядах s[1],...,s[m-1].

Пусть m - значение лежащее на вершине стека обхода дерева вызова. Тогда это значение соответствует некоторому вызову процедуры G(m-1,h), который в свою очередь однозначно определяет узел дерева обхода, лежащий на пути из листа, соответствующего текущему кодовому слову в корень дерева, при этом узел G(m-1,h) является первым узлом типа G, лежащим на этом пути. Непосредственного предка узла G(m-1,h) обозначим G*(m,...). Узел G*(m,...) может соответствовать вызову как процедуре G, так и процедуре GR, при этом для процедуры G s[m] в текущем кодовом слове равно 0, для процедуры GR - 1. Пусть узел GR(m-1,...) непосредственный правый потомок вершины G*(m,...). Тогда путь из корня дерева обхода к листу, соответствующему следующему кодовому слову за текущим в G(n,k), может быть описан как

G(n,k),...,G*(m,...), GR(m-1,..), G(m-2,..),...,G(p,...),

где р - уровень узла следующего кодового слова. Т. е. путь из корня рева обхода к листу соответствующему следующему кодовому слову совпадает на участке G(n,k),..., G*(m,...) с путем к текущему кодовому слову, затем осуществляется переход по правой ветви узла G*(m,...), после чего путь проходит только по левым ветвям узлов дерева.

 

G(n,k)

 
 

 


G*(m,...)

 
 


s[m-1] 1-s[m-1]

 

G(m-1,h) GR(m-1,...)

1 1

GR(m-2,h-1) G(m-2,...)

       
   

 


(текущее кодовое слово) (следующее кодовое слово)

 

Таким образом, для перехода к следующему кодовому слову мы должны преобразовать текущее кодовое слово в разрядах 1,...,m, а также занести в стек значения уровней вызова процедуры G - m-2,...,p+1. В преобразовании кодового слова одним из изменяемых разрядов является s[m], а другой может быть вычислен на основе теоремы 4.1по следующей схеме:

случай 1. s[m]=0, h>1, это означает, что первые (m-1) разрядов текущего кодового слова являются последним кодовым словом в G(m-1,h), а начало следующего кодового слова представляет собой первое кодовое слово в GR(m-1,h-1), т. е.

1h-210m-h-110... переходит в 1h-200m-h-111...

­ ­

s[m] s[m]

если s[m]=0, h=1, тогда

0m-210... переходит в 0m-201...

­ ­

s[m] s[m]

случай 2. s[m]=1, h>0, это означает, что первые (m-1) разрядов текущего кодового слова являются последним кодовым словом в G(m-1,h), а начало следующего кодового слова представляет собой первое кодовое слово в GR(m-1,h), т. е.

1h-100m-h-211... переходит в 1h-110m-h-210...

­ ­

s[m] s[m]

если s[m]=1, h=0, тогда

0m-201. .. переходит в 0m-210...

­ ­

s[m] s[m]

Таким образом, вторым изменяемым разрядом является

s[h-1], если s[m]=0 и h>1

s[m-1], если s[m]=0 и h=1

s[h], если s[m]=0 и h>1

s[m-1], если s[m]=1 и h=0.

Нам осталось установить только значение параметра p, от которого зависит число новых узлов дерева, с не пройденными правыми ветвями.

Если h=0 или h=m-1, то в стек никакие новые узлы не добавляются, поскольку узел G(m-1,h) является листом, однако для последующих преобразований h должно быть изменено на h+1. С другой стороны, в случае h¹0 и h¹m-1 мы должны включить в стек узлы m-1 ,m-2,. . ., h+1, за исключением того случая, когда s[m-2]=...=s[1]=0; в этом же случае в стек включается только m-1. Значение h должно быть вычислено заново, и, так как среди s[m-1], s[m-2],...,s[h+1] единицей может быть только s[m-1], мы можем h вычислить как h-s[m-1]. Если при этом h становиться равным 0, мы должны иметь s[m-2]=...=s[1]=0.

На основе этих рассуждений строится следующая программа:



<== предыдущая лекция | следующая лекция ==>
Генерация мультимножеств. | Введение.


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.011 сек.