380 likes | 478 Views
ГЕНЕРИСАЊЕ ОСНОВНИХ КОМБИНАТОРНИХ ОБЈЕКАТА. др Ђура Паунић Департман за математику и информатику, ПМФ Нови Сад. Генерисање основних комбинаторних објеката. Комбинаторни објекти су врло погодни за програмирање: Захтевају врло мало предзнање за формулацију и схватање проблема.
E N D
ГЕНЕРИСАЊЕ ОСНОВНИХ КОМБИНАТОРНИХ ОБЈЕКАТА др Ђура Паунић Департман за математику и информатику, ПМФ Нови Сад
Генерисање основних комбинаторних објеката Комбинаторни објекти су врло погодни за програмирање: • Захтевају врло мало предзнање за формулацију и схватање проблема. • Поступци су алгоритамске природе тако да је њихово програмирање једноставно. • Ручно генерисање комбинаторних објеката је врло досадно и лако се греши.
Погодни примери у настави • Комбинације без понављања • Комбинације са понављањем • Варијације са понављањем • Пермутације у лексикографском поретку • Општи поступак генериања комбинаторних објеката бектреком • Краљице на шаховској табли.
Комбинације без понављања Када се комбинације без понављања уреде, коришћењем лексикографског поретка, тада се добија следећи низ: (1, 2, 3) (1, 2, 4) (1, 2, 5) (1, 3, 4) (1, 3, 5) (1, 4, 5) (2, 3, 4) (2, 3, 5) (2, 4, 5) (3, 4, 5)
Комбинације без понављања (1, 2, 3) (1, 2, 4) (1, 2, 5)
Комбинације без понављања (1, 3, 4) (1, 3, 5) (1, 4, 5)
Комбинације без понављања (2, 3, 4) (2, 3, 5) (2, 4, 5)
Комбинације без понављања (3, 4, 5)
const maxn = 20; type niz = array[0 .. maxn] of integer; procedure print(var a : niz; k : integer); var j : integer; begin for j := 1 to k do write(a[j]:4); writeln end; (* print*) Комбинације без понављања
Комбинације без понављања procedure kombinacije(n, k : integer; var ok : boolean); var a : niz; i : integer; begin if (1 <= n) and (k <= maxn) and (1 <= k) and (k <= n) then
begin ok := true; i := 1; a[1] := 0; while i > 0 do begin while a[i] < n – k + i do begin a[i] := a[i] + 1; if i < k then begin a[i+1] := a[i]; i := i + 1 end else print(a, k) end; i := i - 1 end end else ok := false end; (* kombinacije *)
Рекурзивне комбинације без понављања Рекурзивне процедуре се најлакше реализују тако да се направи унутрашња рекурзивна процедура, а у процедури се изведе иницијализација и позове унутрашња процедура procedure rkombinacije(n, k : integer; var ok : integer); var a : niz; i : integer;
procedure nadji(i : integer); begin if i <= k then begin a[i] := a[i-1]; while a[i] < n - k + i do begin a[i] := a[i] + 1; nadji(i+1) end end else print(a, k) end; (* nadji *)
begin if (1 <= n) and (k <= maxn) and (1 <= k) and (k <= n) then begin ok := true; a[0] := 0; nadji(1) end else ok := false end; (* rkombinacije *)
Комбинације са понављањем • Комбинације са понављањем се генеришу истим поступком као и комбинације без понављања, јер постоји бијекција између комбинација без понављања од n + k − 1 објекта k-те класе и комбинација са понављањем од n објеката k-те класе. • Ова бијекција се просто реализује одузимањем редом бројева 0, 1, ..., k − 1 од комбинација без понављања
Комбинације са понављањем (1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), − 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 2), (1, 2, 3), (1, 4, 5), (2, 3, 4), (2, 3, 5), (2, 4, 5), (3, 4, 5). − 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 (1, 3, 3), (2, 2, 2), (2, 2, 3), (2, 3, 3), (3, 3, 3).
Рекурзивне комбинације са понављањем procedure printp(var a : niz k : integer); var j : integer; begin for j := 0 to k - 1 do write(a[j+1]-j:4); writeln end; (* printp*) procedure rpkombinacije(n, k : integer; var ok : boolean); var a : niz; i : integer;
procedure nadji(i : integer); begin if i = k+1 then printp(a, k) else begin a[i] := a[i-1]; while a[i] < n + i - 1 do begin a[i] := a[i]+1; nadji(i+1) end end end; (* nadji *)
begin if (1 <= n) and (1 <= k) and (k <= maxn) then begin ok := true; a[0] := 0; nadji(1) end else ok := false end; (* pkombinacije *)
Варијације са понављањем Лексикографским уређивањем варијација са понављањем добија сеследећи низ 111, 112, 113, 121, 122, 123, 131,132, 133, 211, 212, 213, 221, 222, 223, 231, 232, 233, 311, 312, 313, 321, 322, 323, 331, 332, 333.
Варијације са понављањем procedure varip(n, k : integer); var a : niz; i : integer; begin i := 1; a[1] := 0; while i > 0 do begin while a[i] < n do begin a[i] := a[i] + 1; if i < k then begin a[i+1] := 0; i := i + 1 end else print(a, k) end; i := i - 1 end end; (* varip *)
Примена варијација са понављањем for i1 := dgr[1] to ggr[1] do for i2 := dgr[2] to ggr[2] do . . . . . . . . . . . . . for ik := dgr[k] to ggr[k] do obrada(k, i1, i2, ..., ik);
Нека је процедура obradaсамо испис индекса procedure obrada(var k : integer; var indeks : niz); var j : integer; begin for j := 1 to k do write(indeks[j]:4); writeln end; (* obrada *)
procedure indeksi(k : integer; var dgr, ggr, indeks : niz); var i : integer; begin i := 1; indeks[1] := dgr[1] - 1; while i > 0 do begin while indeks[i] < ggr[i] do begin indeks[i] := indeks[i] + 1; if i < k then begin i := i + 1; indeks[i] := dgr[i] - 1 end else obrada(k, indeks) end; i := i - 1 end end; (* indeksi *)
Пермутације Нека су пермутације уређене лексикографски. 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 2 6 5 8 7 4 3 1 2 6 7 1 3 4 5 8 • Почев од краја пермутације, уочимо низ растућих елемената (8 7 4 3 1). • Назовимо овај низ крајњи низ. • У крајњем низу уочимо први елемент (7) који је већи од елемента испред крајњег низа (5) и заменимо та два елемента (7 8 5 4 3 1). • Напишимо добијени крајњи низ (8 5 4 3 1) у обрнутом редоследу (1 3 4 5 8).
Процедура за пермутације у лексикографском уређењу procedure LexiPerm(n : integer; var ok : boolean); var a : niz; i, j, k, pom : integer; begin if (1 <= n) and (n <= maxn) then begin ok := true; for i := 1 to n do a[i] := i;
repeat print(a, n); k := n - 1; while (k > 0) and (a[k] > a[k+1]) do k := k - 1; if k > 0 then begin j := n; while a[k] > a[j] do j := j - 1; pom := a[k]; a[k] := a[j]; a[j] := pom;
i := (n - k) div 2; for j := 1 to i do begin pom := a[k+j]; a[k+j] := a[n+1-j]; a[n+1-j] := pom end end until k = 0 end else ok := false end; (* LexiPerm *)
Рекурзивне пермутације procedure rpermutacije(n : integer; var ok : boolean); var a : niz; i : integer;
procedure nadji(i : integer); var mesto, temp : integer; begin for mesto := i to n do begin temp := a[i]; a[i] := a[mesto]; a[mesto] := temp; if i < n then nadji(i + 1) else print(a, n); temp := a[i]; a[i] := a[mesto]; a[mesto] := temp end end; (* nadji *)
begin if (1 <= n) and (n <= maxn) then begin ok := true; for i := 1 to n do a[i] := i; nadji(1) end else ok := false end; (* rpermutacije *)
Општи поступак претраживања Претходни алгоритми су углавном били специјални случајеви решавања следећег апстрактног проблема:
У скупу свих могућих n-торки, за произвољно n, треба наћи скуп решења (бар једно или све). При том се n-торка (r1,r2,...), коначне, али неодређене дужине, назива решење ако задовољава кретеријуме за проверу решења. Свака компонента ri припада коначном скупу Si могућих елемената за ту компоненту. Скупови Si могу за сваку компоненту бити различити.
procedure backtrack; var i : integer; begin i := 1; dopustiv(T[1], S[1], r); while i > 0 do begin while not prazan(T[i]) do begin izaberi(r[i], T[i]); izbaci(r[i], T[i]); if proveriresenje(r) then print(r); i := i + 1; dopustiv(T[i], S[i], r) end; i := i - 1 end end; (* backtrack *)
procedure rbacktrack; procedure proba(i : integer); begin dopustiv(T[i], S[i], r); while not prazan(T[i]) do begin izaberi(r[i], T[i]); izbaci(r[i], T[i]); if proveriresenje(r) then print(r); proba(i + 1) end end; (* proba *) begin proba(1) end; (* rbacktrack *)
Коришћење скупова није увек погодно, јер ти скупови могу бити врло велики. Како сваки коначан скуп може да се линеарно уреди може се претпоставити да су скупови Siлинеарно уређени. Тада је могуће алгоритам модификовати тако да се користи само најмањи елемент у скупу на следећи начин:
procedure ebacktrack; var i : integer; begin i := 1; a[1] := - maxint; a[i] := nadjisledeci(a[i],S[i],r); while i > 0 do begin while a[i] < granica[i] do begin r[i] := a[i]; a[i] := nadjisledeci(a[i],S[i],r); if proveriresenje(r) then print(r); i := i + 1; a[i] := - maxint a[i] := nadjisledeci(a[i],S[i],r) end; i := i - 1 end end; (* ebacktrack *)
К Р А Ј Хвала на пажњи