Разделы
Главная Сапромат Моделирование Взаимодействие Методы Инновации Индукция Исследования Факторизация Частоты
Популярное
Как составляется проект слаботочных сетей? Как защитить объект? Слаботочные системы в проекте «Умный дом» Какой дом надежнее: каркасный или брусовой? Как правильно создавать слаботочные системы? Что такое энергоэффективные дома?
Главная »  Математика 

1 ... 5 6 7 8 9 10 11 ... 28

Алгоритм 4.9. Программа на Pascal\решения задачи Счастливый билет Program Lucky ticket; {Счастливый билет uses CRT, DOS; Const

max n=20; Type

Vector=array [1. .max n] of Longlnt;

Procedure ( var ; var a , b : Vector ;

n, m:Integer ) ;

S : Longlnt;

i : Integer; begin

S:=a[l];

for i:=l to n-1 do S:-S + (2*b[i]-l) *a[i + l] ; if S=m then begin Write(f, a[1]) ; for i:=l to n-1 do begin

if b[i]=l then Write (f,+) else Write (f,-); Write (f,a[i + l]) ; end;

WriteLn(f, = \S:4, - число найдено!);

end; end;

Procedure var var

n,m: Integer ) ;

b: Vector; i : Integer;

begin

for i:=l to n do b[i]:=0; while b[n]ol do begin Summa(f,a,b,n,m); i: =1 ;

while b[i]=l do begin

b[i]:=0;

i:=1+1; end;

b[i]:=1; end; end;



Var {Main}

a :Vector;

n,m, i :Integer; f :Text; {Текстовый файл)

Hour,Minute,Second, SeclOO :Word; rHour,rMinute,rSecond, rSeclOO :Word; delta rLonglnt; begin(Main)

Assign(f,Number.in); Reset (f);{Файл открыт для чтения) Read(f.n); {Ввог количества цифр) Read(f,m); {Ввод счастливой суммы) for i:=l to n do Read(f,a[i]); Close(f);

Assign(f, Number.out)

Rewrite (f5; (Фай/ открыт для записи) GetTime(Hour,Minute,Second,SeclOO) ; SubSet(f,a,n,m);

GetTime(rHour,rMinute,rSecond,rSeclOO);

delta:-rHour-Hour; delta:-delta*6 0 + rMirmte-Minute;

delta:=delta*60+rSecond-Second;

delta:=delta*100+rSeclOO-Secl00;

WriteLn(f); WriteLn(f,Время счета=,

delta div 100, , ,delta mod 100, c ) ; Close (f); end{Main}.

4.5. Генерация размещений с повторениями

Порождение множества всех размещений с повторениями длины к из элементов {я0, ал,. , ап {) эквивалентно генерации множества /-разрядных чисел в системе счисления с основанием и: на г-м месте в размещении будет располагаться элемент а:. если цифра в разряде соответствующего числа равна Всего размещений с повторениями п . Например, для к= 2 и п = 3 все наборы длины два в системе счисления с основанием три можно записать: 00, 01, 02, 10, 11, 12. 20, 21, 22. Тогда эквивалентные размещения примут вид

(аоя0), (fl0fli), (а0а2), (а^), (а^), (а{а2), (а2а0), (а2ах), (а2а2).

Алгоритм 4.10 использует фиктивный элемент при порождении наборов длины к в системе счисления с основанием и, где



bpiQ, 1,..., п 1},/ = О, 1,..., к, т.е. - это цифры генерируемого числа в системе счисления с основанием п.

Алгоритм 4.10. Счет в системе счисления с основанием п для порождения всех к-разрядных наборов

for / = 0 to к do bj = 0;

Print{bk vbk 2, ..,b0), /=0;

С

whilebj =n-ldo .

l -* tI;

6; =6, +1.

while 1 do

4.6. Порождение сочетаний

Обычно требуются не все подмножества множества {alt а ...., ап}, а только те, которые удовлетворяют некоторым ограничениям. Особый интерес представляют подмножества фиксированной длины к, С* сочетаний из п предметов по А: штук. Как обычно,

предполагаем, что основным множеством является множество натуральных чисел {1, 2,..., и}; таким образом, будем порождать все сочетания длины киз целых чисел {1, 2,..., л}. Так, например, С\ =20 сочетаний из шести предметов по три (т.е. трехэлементные подмножества множества записываются в лексиког-

рафическом порядке следующим образом:

123 135 234 256

124 136 235 345

125 145 236 346

126 146 245 356 134 156 246 456

Сочетания в лексикографическом порядке можно порождать последовательно простым способом. Начиная с сочетания {1, следующее сочетание находится просмотром текущего сочетания справа налево с чтобы определить место самого правого элемента, который еще не достиг своего максимального значения. Этот элемент увеличивается на единицу, и всем элементам справа от него присваиваются новые возможные наименьшие значения, как показано в алгоритме 4.11. Алгоритм порождения всех сочетаний линеен, его сложность



Алгоритм 4.11. Порождение сочетаний

со = -1;

for i = 0 to k do = i;

Print{ci,c2,...,ch)\ j=k;

whilej * 0 doi while Cj = n-k +jdo j =j -1;

Cj =Cj +1;

for i = j + \to к do Cj =c, , +L

Задача. Выпуклый многоугольник. Дано множество пар целых чисел (хуУу), (х2,у2),..., (х„,у„) - координаты точек на плоскости. Написать программу выделения тех точек из заданного множества, которые являются вершинами выпуклого многоугольника, содержащего все остальные точки. Исходные данные представлены в текстовом файле, имеющем следующую структуру. Первым числом в файле является целое л - количество точек. Последующие числа определяют п пар целых (х, у.) - координаты точек. Результаты расчетов, признаки принадлежности исходных точек выпуклому многоугольнику: 0 - точка не принадлежит, 1 - точка принадлежит, сохранить в текстовом файле.

Пример файла исходных данных:

0099512327 11 5467 15673457788764 Выходной файл для данного примера:

1 1 1 0 1 0 0 0 1 0 0 0 0 1 0

Решение. Если не применять специальных методов, то в качестве решения можно использовать следующий алгоритм. Ясно, что точка является вершиной выпуклого многоугольника, если она не лежит ни в одном вершинами которых

являются исходные точки {х^уу), (х2,у2),..., (хп,уп), без рассматриваемой точки (X/У,). Всего треугольников из п точек можно составить С„3 + 0{пг). Тогда сложность задачи полного перебора

угольников для каждой точки (Х/У,) составит 0(п). Реализация данного подхода представлена программой на языке Pascal в алгоритме 4.12.



Алгоритм 4,12. Программа поиска точек выпуклой оболочки

Program 5tart Envelope; iВыпуклая оболочка} uses CRT,DOS; const n max=100;

type Vector-array[I..n max] of Integer; Combine=array[0..3] of Integer;

var f :Text; [Текстовый файл)

x,y :Vector; {Координаты точек}

z :Vector; {Характеристический вектор выпуклой оболочки }

Procedure Envelope( var с:Combine; n:Integer );

{Формирование оболочки}

Const k :Integer-3; Var

i, a :Integer;

kl,k2,k3 :Integer;

signl,sign2,sign3 :Integer;

begin

kl: -t/lVj ; Se.-C(2.j*, r?.y;=<T rfVj ; for i:=l to n do begin

if (i=kl) or (i = k2) or (i=k3) then continue; a:=(x[kl]-x[i])*(y[k2]-y[i] )-[x[k2]-x[i])*(y[kl]-y[i]); if a=0 then continue; signl =a div abs (a); a:=(x[k2]-x[i])*(y[k3]-y[i])-(x[k3]-x[i])*(y[k2]-y[i]); if a=0 then continue; sign2 : ==a div abs (a) ; a: = (x[k3]-x[i])My[kl]-y[i])-[x[kl]-x[i])*(y[k3]-y[i])t if a=0 then continue; sign3:=a div abs (a); if (signl=sign2) and (sign2 = sign3) then z[i]:=0; end; end;

Procedure var

Var i : Integer;

begin

WriteLn(f);

for i:=l to n do

end;



Procedure Combination( n:Integer );

{Генерация сочетаний из п по Const k :Integer=3; {Длина сочетания} Var с :Combine; {Сочетание} i,j . Integer;

begin

for i:=l to к do c[i]:=i;

j:=l;

while j<>0 do begin {Print(с,k);} Envelope(c,n) ; j:=k;

while c[j]=n-k+j do j:=j-l; c[j]:=c[j]+l;

for i:=j+l to k do c[i]:=c[i-l]+l; end; end;

Var {Main)

i,n :Integer; {Числе исходных точек) begin {Main}

Assign(f, Envelope.in);

Reset(f); {Файх открыт для чтения)

Read(f,n); {Ввод данных}

for i:=l to n do begin Read(f,x[i],у[il); zfi):=l;end; Close(f);

Assign(f,Envelope.out);

Rewrite(f); {Фай* открыт для записи}

Combination(n);

WriteLn(f); {Результаты: номера точек выпуклой оболочки} for i:=l to n do Write(f,z[i], v) ; Close(f); end. {Main}

4.7. Порождение композиций и разбиений

Рассмотрим задачу порождения разбиений положительного числа п в последовательность неотрицательных целых чисел fci, z2,..., Ьтакчтоггг ... +3f п.

Разбиение {ц, zb..., zk) называется композицией числа п, если учитывается порядок чисел zr Как правило, представляют интерес композиции, в которых либо все щ > 0, либо все Zj > 0.



Разбиение {ц, z2,-, Zk) назътштсяразбиением числа п, если все Zi>0 и порядок чисел Z, не важен. По сути разбиение {Z\, Z2,---, Z/J числа я является мультимножеством (см. п. 1.8).

Рассмотрим примеры разбиения числа п = 3. (1, 2), (2, 1) - все композиции числа три из двух частей, > 0. (1, 1, 1) - все композиции числа три из трех частей, > 0. (О, 3), (1, 2), (2, 1), (3, 0) - все композиции числа три из двух частей, z, > 0.

(3), (1, 2), (1, 1, 1) - все разбиения числа три.

Композиции О

Композицию {zi, z2,...,zk), гдег,> 0, числа^ +Z2 +-+zk = п можно интерпретировать следующим образом. Каждое значение г,- = 1, + 1,+ ... + 1/ представим как сумму единиц, количество которых Zj- Индекс у элемента 1, показывает его принадлежность разложению числа Zj. Таким образом, мы ввели к типов различных элементов {1[, 12, .., 1д}, значение каждого из них равно единице. Теперь любую композицию можно представить как сумму, составленную из п произвольных единиц множества {\ь \2,..., \к). Суммируя подобные единицы 1;с одинаковыми индексами, получим соответствующие значения z, композиции. Данное соответствие является взаимно однозначным, откуда и следует, что число композиций равно числу сочетаний с повторениями С\ = C*~J j = C+k t. Каждое из сочетаний С^, можно интерпретировать как расстановку 1 и О

длины п + к - в которой п единиц и к - 1 нуль, т.е. каждому сочетанию ставим в соответствие (п + к - 1)-разрядное число из единиц и нулей; верно и обратное. Суммируя в таком числе слева направо единицы между нулями (их к - 1), будем получать соответствующие значения членов Z\ (их к) композиции. Например, одному из Сп+к-1 =С117+7-1 сочетаний 11011100111101111111010 соответствует композиция (2,3,0,4,7,1,0) числа 17.

Ясно, что методы предыдущего раздела генерации подмножеств множества легко применить к последовательному порождению рассмотренных композиций 0.

Композиции > О

Удобное представление композиций получается из рассмотрения целого числа п как отрезка прямой, состоящего из отрезков единичной длины. Линия разделена п - 1 точками, и композиция



ч--2-- - 1 - --2---2-* +- I

--®- 0- -®-- --®-

получается пометкой некоторых из них. Элементами композиции являются просто расстояния между смежными точками. На рисунке показано графическое представление композиции (2,1,2,2,1) для числа п = 8. Очевидно, что каждая композиция числа соответствует способу выбора подмножества из п - 1 точек. Каждой точке можно сопоставить двоичную цифру, и, таким образом, композиции п будет соответствовать (п - 1)-разрядное число. В этой интерпретации композиция из к частей соответствует^ - 1)-разрядномучислу ровно с к - 1 единицами, и поэтому существует Скп~ { таких композиций.

Воспользуемся методами предыдущего раздела для генерации композиций щ> 0. Учитывая, что в композиции z\ + % +... + Щ = и каждый из > 0, тогда для новых переменных = - 1,(г, > 0) соответствующая композиция будет для числа = = г\ + г2 +--+ гь гт О-Генерация слагаемых /*; Ю композиции (г\, гъ..., гк) подробно разобрана в предыдущем разделе, добавляя к каждому из по единице, получим слагаемые 0 композиции {Z\,Z2, - , Zk}-

Разбиения

Разбиения п отличаются от композиций п тем, что порядок компонент не важен, так что, например, не делается различия между, скажем, 1+1+2, 1+2+1,2+1+1. Таким образом, разбиение п можно рассматривать как которое записы-

вается следующим способом:

{Wj zi,m2 z1,...,mk zk},

где имеется вхождений z\, вхождений z- >Щ вхождений

к

и т. д. ии = л,г|. Каждое разбиение удовлетворяет условию

> > ... > Рассмотрим пример генерации разбиений для п = 7. Последовательность генерации разбиений данного примера далее будет положена в основу алгоритма порождения полного

списка разбиений.

Идея приведенного списка разбиений состоит в том, чтобы переходить от одного разбиения к следующему, рассматривая самый правый элемент mк zk разбиения. Если достаточно ве-



лико (т.. > 1), можно исключить два для того, чтобы добавить еще одно zk + 1 (или включить одно zk 1, если в текущий момент его нет). Если тк= \, то mk izk-i + mkzk достаточно велико для того, чтобы добавить Zk-\ + 1. Все, что остается, превращается в соответствующее число единиц и формируется новое разбиение.

[74)

= {1,1,1,1,1,1,1

t1*2 5-1}

= {2,1,1,1,1,1)

{2*2,3*1)

= {2,2,1,1,1)

{3*2,1*1)

={2,2,2,1)

{1*3,4-1)

= {3,1,1,1,1)

{1*3,1*2,2

=(3,2,1,1)

[1*3,2*2}

={3,2,2)

{2*3,1*1)

=(3,3,1}

{1-4,3-1)

= {4,1,1, 1}

{1*4, 1 2, 1

={4,2,1)

(1*4, 13)

=(4,3)

{1*5,2 1)

= {5,1,1}

{1*5, 1 2)

={5,2}

{1*6,1*1)

={6,1)

£1*7)

= {7}

Алгоритм использует рассмотренный процесс для порождения всех разбиений числа п.

Алгоритм 4.13. Генерация разбиений числа п

к= 1;

г д = 0; т ! =0; Ц = п+ 1;

Z\ = 1;

Print{ml zvm1 z1,...,mk*zk); Summa = mhzk;

while k 0 do


[k=k+l



Алгоритм 4.13 линеен, так как число операций, необходимых для перехода от одного разбиения к другому, ограничено константой, не зависящей от п и к.

Программа на языке Pascal реализации рассмотренного метода генерации разбиений чисел приводится в алгоритме Отметим, что в программе число для разбиения п читается из файла, а порождаемые разбиения сохраняются в файле. Попутно программа вычисляет полное время генерации всех разбиений с точностью до сотых долей секунды, которое сохраняется в конце

файла сгенерированных разбиений.

Алгоритм 4.14. Программа на Pascalе генерации разбиений

числа п

Program Start Divide; {Разбиение числа

uses CRT,DOS; Const

max n=100; { n<=max n }

Type

Vector=array[-l..max n] of Integer; Var

f :Text; z,m :Vector;

Procedure var k: Integer );

(Печать разбиения}

i :Integer; begin

Write (f, {) ; for i:=l to k do begin Write(f,m[i],*,z [i]) ; if iok then Write (f ) ; end;

Writel.n (i, } ); end; {Print}

Procedure числа

k, Sum :Integer; begin; k:=l; z[-l]:=0; m[-l]:=0;





1 ... 5 6 7 8 9 10 11 ... 28