Wyklad 04

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 1

Techniki budowania algorytmów

Co w ramach wykładu?

1. Rekurencja

2. Dziel i zwyciężaj

3. Programowanie dynamiczne

4. Metoda zachłanna

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 2

Dziel i zwyciężaj

Schemat ogólny

Trzy zasadnicze kroki:
1.transformacja danych x na dane x

1

, . . . , x

k

o mniejszym rozmiarze;

2.rozwiązanie problemu dla danych x

i

(i = 1, . . . , k);

3.obliczenie rozwiązania dla danych x na podstawie wyników otrzymanych
w punkcie 2.

W naturalny sposób implementowane są jako procedury rekurencyjne:

function DiZ(x)

if x jest małe lub proste then return AdHoc(x)
przekształć x na x

1

, . . . , x

k

o mniejszym rozmiarze

niż x
for i ← 1 to k do y

i

DiZ(x

i

)

na podstawie y

1

. . . y

k

oblicz rozwiązanie y dla x

return y

Bitwa pod Austerlitz, 2 grudnia 1805 r. – zwycięstwo wojsk Napoleona nad
liczniejszymi
o około 15 000 żołnierzy połączonymi armiami Austrii i Rosji.

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 3

Przykład 1 – Wyszukiwanie binarne

Wyszukiwanie binarne

Problem: czy klucz x znajduje się w posortowanej tablicy S,
zawierającej n kluczy?
Dane wejściowe: całkowita liczba dodatnia n, tablica kluczy S
indeksowana od 1 do n oraz klucz x.
Dane wyjściowe: location – lokalizacja klucza x w tablicy S (0, jeśli x
nie występuje w S)

Algorytm wyszukiwania binarnego
Jeżeli x jest równe elementowi środkowemu, kończymy. W przeciwnym
przypadku:
1.Dzielimy tablicę na dwie podtablice o rozmiarze mniej więcej dwa razy
mniejszym od oryginalnej. Jeżeli x jest mniejsze od elementu
środkowego, wybieramy lewą podtablicę. Jeśli x jest większe od
elementu środkowego, wybieramy prawą podtablicę.
2.Zwyciężamy (rozwiązujemy) podtablicę poprzez określenie, czy x do
niej należy. O ile podtablica nie posiada dostatecznie małych rozmiarów,
należy wykorzystać rekurencję.
3.Otrzymujemy rozwiązanie problemu tablicy na podstawie rozwiązania
problemu podtablicy.

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 4

Wyszukiwanie binarne c.d.

int location(int low, int high)
{

int mid;
if (low > high)

return 0;

else {

mid = (low+high)/2;

if (x == S[mid])

return mid;

else if (x < S[mid])

return location(low, mid-1);

else

return location(mid+1, high);

}

}

Operacja podstawowa:

porównanie x z S[mid]

Rozmiar danych wejściowych:

liczba n elementów
tablicy S

Złożoność czasowa w
najgorszym przypadku:

W(n) = W(n/2) + 1 , W(1) = 1

W(n) = lgn + 1

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 5

Przykład 2 – Sortowanie przez scalanie

Sortowanie przez scalanie

Problem: posortować n kluczy w ciąg niemalejący
Dane wejściowe: całkowita liczba dodatnia n, tablica kluczy S
indeksowana od 1 do n.
Dane wyjściowe: tablica S, zawierająca klucze w porządku
niemalejącym
Algorytm sortowania przez scalanie
1.Dzielimy tablicę na dwie podtablice o rozmiarze mniej więcej dwa razy
mniejszym od oryginalnej.
2.Zwyciężamy (rozwiązujemy) każdą podtablicę, sortując ją. O ile
podtablica nie posiada dostatecznie małych rozmiarów, należy
wykorzystać rekurencję.
3.Łączymy rozwiązania podtablic poprzez scalenie ich w jedną
posortowaną tablicę.

MERGE-SORT(A, p, r)
if p < r

then q ← (p + r)/2

MERGE-SORT(A, p, q)
MERGE-SORT(A, q+1, r)
MERGE (A, p, q, r)

Jak scalić dwie posortowane tablice w
jedną posortowaną tablicę w czasie
(n)?

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 6

Sortowanie przez scalanie c.d.

void merge(Item c[], Item a[], int n, Item b[], int m)
{

for (int i = 0, j = 0, k = 0; k < n + m; k++)

{

if (i == n) { c[k] = b[j++]; continue; }
if (j == m) { c[k] = a[i++]; continue; }
c[k] = (a[i] < b[j]) ? a[i++] : b[j++];

}

}

Funkcja scalająca dwie uporządkowane tablice a i b w jedną
uporządkowaną tablicę c.

Koszt

Dziel

znalezienie środka przedziału zajmuje czas stały:

(1)

Zwyciężaj

rekurencyjne rozwiązanie dwóch podproblemów o

rozmiarze n/2, co daje czas 2T(n/2)
Połącz

merge działa w czasie (n)

)

log

(

1

,

)

(

)

2

/

(

2

1

,

)

1

(

)

(

n

n

n

n

n

T

n

n

T

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 7

Przykład 3 – Sortowanie szybkie

Algorytm szybkiego sortowania QS (Quick-sort )

W każdym kroku algorytmu, elementy sortowanego ciągu e

l

, ..., e

r 

rozdzielane, względem wybranego elementu v, na podzbiór elementów
mniejszych i podzbiór elementów większych od v (element v nazywa się
medianą).

{e

l

, ..., e

j-1

} < v <= {e

j+1

, ..., e

r

}.

W ten sposób znana jest ostateczna pozycja elementu v w końcowym
uporządkowaniu : element v będzie umieszczony na pozycji j-tej.

Następnie każdy z podzbiorów {e

l

, ..., e

j-1

} oraz {e

j+1

, ..., e

r

} jest sortowany

osobno według tego samego algorytmu.

Przykład rozdzielania zbioru - podstawowy krok
algorytmu QS

Dla ciągu, który chcemy uporządkować niemalejąco:

10, 5, 7, 8, 14, 12, 3, 5, 1

przyjmijmy, że v jest pierwszym elementem ciągu: v = 10. Podzbiór
elementów mniejszych od v to {5,7,8,3,5,1}, a podzbiór elementów
większych lub równych v to {14,12}:

{5,7,8,3,5,1} < 10 <= {14,12}.

Niech v = 5 dla lewego podzbioru. Element 5 jest większy od 3 i 1, a
niewiększy od 5, 7, 8:

{3,1} < 5 <= {5,7,8}

 

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 8

Sortowanie szybkie c.d.

Algorytm

 

QuickSort(l, r);

if  l < r  then
j := Partition(l, r);

(*algorytm rozdzielania*)

QuickSort(l, j-1);

(*sortowanie elementów mniejszych

od v*)

QuickSort(j+1, r)

(*sortowanie elementów

niemniejszych niż v*)

int Partition(l, r)

e := c[l];

//element dzielący

while (l < r)

while ((l < r)  (c[r] >= e)) r r – 1

while ((l < r)  (c[l] < e)) ll + 1

if (l < r) then c[l]  c[r]

return l;

Algorytm  rozdzielania

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 9

Sortowanie szybkie c.d.

Czas działania algorytmu quicksort

1. Przypadek najgorszy – procedura dzieląca tworzy jeden obszar

złożony z n – 1 elementów, a drugi tylko z 1 elementu.

W(n) = W(n – 1) + (n)

(koszt podziału wynosi (n))

Ponadto W(1) = (1), zatem

2. Przypadek najlepszy – podział na obszary o rozmiarach (około) n/2

B(n) = 2B(n/2) + (n)

co daje zależność B(n) = (n lgn)

3. Przypadek średni

skąd A(n) = (n lgn)

n

k

n

k

n

k

k

n

n

W

n

W

1

2

1

)

(

)

(

)

(

)

1

(

)

(

1

)

(

)

1

(

1

)

(

1

n

p

n

A

p

A

n

n

A

n

p

Średni czas sortowania

podtablic,

kiedy pivotpoint to p

Czas podziału

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 10

Przykład 4 – Jeszcze raz algorytm rozdzielania

Problem:

znaleźć k-ty największy element tablicy S

Dane wejściowe:

całkowita liczba dodatnia n, tablica liczb S

indeksowana od 1 do n oraz k takie, że 1  kn.

Dane wyjściowe:

element select tablicy S taki, że dokładnie k-1

elementów tablicy S jest większych od select.

1.

Prosty algorytm – k-krotne wyszukiwanie maksimum 

ogólnie złożoność (n

2

)

2.

Posortowanie tablicy i odczytanie k-tego elementu  j.w.

2. Idea algorytmu Hoare:

i.

Rozdzielić elementy tablicy na mniejsze i większe względem
pewnego elementu m, np. względem pierwszego lub ostatniego
elementu tablicy. Niech x będzie liczbą elementów większych od m.

ii. Jeżeli  x > k-1, to  elementu k-tego szukamy wśród elementów

większych od m, stosując to samo postępowanie.

iii. Jeżeli  x = k-1, to m jest szukanym, k-tym co do wielkości

elementem tablicy.

iv. Jeżeli  x  < k-1, to wśród elementów mniejszych od m szukamy (tą

samą metodą) elementu (k-x-1)-tego co do wielkości.

Wyznaczanie k-tego największego elementu w ciągu

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 11

Algorytm Hoare

Przykład

Szukamy 6-tego elementu w ciągu:

c = (6, 4, 1, 8, 7, 3, 2, 5, 9, 0).

Jako element rozdzielający przyjmujemy pierwszy wyraz ciągu. Po pierwszym
podziale:

4, 1, 3, 2, 5, 0,

6

, 8, 7, 9

Zgodnie z punktem iv. algorytmu, szukamy teraz elementu drugiego co do
wielkości
(k – x – 1 = 6 – 3 – 1 = 2) w ciągu elementów mniejszych od 6, czyli w ciągu  
4, 1, 3, 2, 5, 0.
Po rozdzieleniu tego ciągu względem 4 otrzymamy

1, 2, 3, 0, 

4

5

bo tylko jeden element jest większy od 4. Na mocy punktu iii. algorytmu
Hoare, 4 jest szukanym, szóstym co do wielkości elementem danego ciągu c.

Jak przebiegną poszukiwania, gdy jako element rozdzielający przyjmiemy
ostatni wyraz ciągu?

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 12

Algorytm Hoare

elem Hoare (e: ciąg, l, p, k: int)
{

j := Partition(l,p);

// j jest pozycją elementu rozdzielającego:

na

// prawo elementy większe, na lewo

elementy

// niewiększe

if (p-j = k-1) then result := e[j]

// e[j] jest mniejsze od dokładnie k-1

elementów

else

if (p-j>k-1) then

// jest co najmniej k elementów większych

od e[j]

result:=Hoare(e, j+1, p, k); 

// e[result] jest k-tym co do wielkości

elementem

// ciągu e[j+1],...,e[p]

else result:=Hoare(e, l, j-1, k-(p-j+1);

// e[result] jest k-(p-j+1)-tym

co do wielkości

// elementem

ciągu e[l],e[l+1],...,e[j-1]

  

return e[result]

// e[result] jest k-tym co do wielkości

elementem

// ciągu e

}

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 13

Koszt algorytmu Partition

Liczba porównań wykonanych w procesie rozdzielania zależy od liczby
elementów znajdujących się w rozważanej części ciągu. W każdej iteracji
pętli "while" wykonujemy tylko jedno porównanie. Pętla "while" jest
wykonywana dokładnie r - l razy. Zatem dla ciągu n elementowego  koszt
algorytmu Partition wynosi:

T(n) = (n).

Koszt algorytmu Hoare

W najgorszym przypadku algorytm Hoare może działać tak źle, jak
algorytm naiwny. Jeżeli dany ciąg jest uporządkowany rosnąco, to w każdym
rekurencyjnym wywołaniu funkcji Partition, liczba elementów mniejszych od
rozdzielającego jest zbiorem pustym. Zatem, o ile trzeba kontynuować
poszukiwania k-tego co do wielkości elementu, kontynuuje się je w ciągu
elementów o jeden krótszym. Biorąc pod uwagę koszt Partition,
otrzymujemy

(n-1) + (n-2) + ... +(n-k) = kn - k(k+1)/2

porównań w przypadku pesymistycznym.
Na szczęście koszt średni algorytmu Hoare jest zdumiewająco dobry.
Udowodniono, że średni koszt algorytmu Hoare jest liniowy O(n).

Algorytm Hoare - złożoność czasowa

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 14

Przykład 5 – Mnożenie (bardzo) dużych liczb

Dane wejściowe: liczy naturalne a i b (długie)
Wynik: iloczyn a·b
Dla prostoty zakładamy, że a i b mają tą samą długość n bitów.
Pomysł:

1.Dzielimy n-bitowe czynniki na części n/2 - bitowe.

a = a

1

·2

s

+a

0

i b = b

1

·2

s

+b

0

,

gdzie s = n/2 i 0  a

1

, a

0

, b

1

, b

0

 2

s

.

2.Zwyciężamy mnożąc przez siebie otrzymane części

c

2

= a

1

·b

1

, c

1

= a

1

·b

0

+ a

0

·b

1

, c

0

= a

0

·b

0

3.Łączymy wyniki i uzyskujemy końcowy wynik

a·b = c

2

·2

2s

+ c

1

·2

s

+ c

0

Podsumowanie:

Mnożenie dwóch liczb n-bitowych zastępujemy

czterema mnożeniami liczb n/2-bitowych, dwoma mnożeniami przez
potęgę 2 (czas liniowy)
i trzema dodawaniami (czas liniowy) . Czyli T(n) = 4T(n/2) + (n)
Stąd: T(n) = (n

2

) , czyli… żaden zysk

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 15

Mnożenie dużych liczb c.d.

Zyskamy, jeśli zamiast czterech mnożeń liczb n/2-bitowych wystarczą trzy.

c

1

= (a

1

+ a

0

)(b

1

+ b

0

) – c

0

c

2

multiply(a, b)

nmax(|a|, |b|) //|x| oznacza długość liczby n

If n jest małe then pomnóż a i b klasycznym algorytmem

return obliczony iloczyn

s  n/2

a

1

 a/2

s

 ; a

0

a mod 2

s

b

1

 b/2

s

 ; b

0

b mod 2

s

zmultiply(a

0

, b

0

)

ymultiply(a

1

+a

0

, b

1

+b

0

)

xmultiply(a

1

, b

1

)

return 2

2s

x + 2

s

(yxz) + z

Tym razem:

co daje ostatecznie T(n) = O(n

log3

) ≈ O(n

1,585

)

1

dla

)

(

)

2

/

(

3

1

dla

)

(

n

n

n

T

n

k

n

T

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 16

Przykład 6 – Mnożenie macierzy

Problem:

wyznaczyć iloczyn dwóch macierzy o wymiarach nn

Dane wejściowe:

dodatnia liczba całkowita n, dwuwymiarowe

tablice liczb A i B z wierszami i kolumnami indeksowanymi
od 1 do n.

Dane wyjściowe:

dwuwymiarowa tablica liczb C (wiersze i kolumny

indeksowane od
1 do n), zawierająca iloczyn macierzy A i B.

Algorytm działający według definicji mnożenia macierzy

MATRIX-MULTIPLY(A, B, n)
for i 1 to n

for j  1 to n

c

ij

 0

for k  1 to n

c

ij

c

ij

+ a

ik

·b

kj

return C

Operacja podstawowa – mnożenie elementów macierzy
Złożoność czasowa: T(n) = (n

3

)

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 17

Mnożenie macierzy c.d.

Metoda Strassena

22

21

12

11

22

21

12

11

22

21

12

11

b

b

b

b

a

a

a

a

c

c

c

c

n/2

n/2

M

1

= (A

11

+ A

22

)(B

11

+ B

22

)

M

2

= (A

21

+ A

22

)B

11

M

3

= A

11

(B

12

- B

22

)

M

4

= A

22

(B

21

B

11

)

M

5

= (A

11

+ A

12

)B

22

M

6

= (A

21

A

11

)(B

11

+ B

12

)

M

7

= (A

12

- A

22

)(B

21

+ B

22

)

C

11

= M

1

+ M

4

M

5

+ M

7

C

12

= M

3

+ M

5

C

21

= M

2

+ M

4

C

22

= M

1

+ M

3

M

2

+ M

6

Złożoność czasowa w każdym przypadku (dla n będącego potęgą 2):

T(n) = 7T(n/2) dla n>1

(nie uwzględniamy 18 dodawań i odejmowań

T(1) = 1

Rozwiązanie rekurencji daje: T(n) = (n

log7

) ≈ (n

2,81

)

czyli składnika18(n/2)

2

)

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 18

Mnożenie macierzy – który algorytm wybrać?

Porównanie algorytmów mnożenia macierzy o wymiarach nn

Algorytm

standardowy

Algorytm

Strassena

Mnożenia

n

3

n

2,81

Dodawania i

odejmowania

n

3

n

2

6n

2,81

– 6n

2

Inne (lepsze?) wyniki:
1.Samuel Winograd (1988) – metoda wymagająca 15 operacji dodawania
i odejmowania, co daje złożoność czasową operacji dodawania i
odejmowania 6n

2,81

– 6n

2

2.Coppersmith i Winograd (1987) – algorytm o złożoności operacji
mnożenia O(n

2,38

),

ale o dużej stałej

Mnożenie macierzy wymaga algorytmu o złożoności co najmniej
kwadratowej. Nikt jeszcze takiego nie znalazł ani nie udowodnił, że
takiego nie ma.

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 19

Dziel i zwyciężaj – Znajdowanie pary najmniej

odległych punktów

Problem

Dane: Zbior P = {(x

1

, y

1

), . . . , (x

n

, y

n

)} współrzędnych punktów

na płaszczyźnie.
Zadanie:

Znaleźć dwa najbliżej położone względem siebie

punkty w P, tj. znaleźć
i,j takie, że d(x

i

, y

i

, x

j

, y

j

) = min{d(x

k

, y

k

, x

l

, y

l

) | 1  k < ln},

gdzie

Siłowe rozwiązanie, polegające na wyliczeniu i porównaniu
odległości między każdą parą punktów, wymaga czasu

2

2

)

(

)

(

)

,

,

,

(

l

k

l

k

l

l

k

k

y

y

x

x

y

x

y

x

d

)

(

2

)

(

2

n

n

n

T

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 20

Strategia Dziel i Zwyciężaj

1.

(a) Sortujemy punkty z P według współrzędnych x i

zapamiętujemy je w tablicy X;
(b) Sortujemy punkty z P według współrzędnych y i zapamiętujemy je w
tablicy Y ;
(c) Znajdujemy prostą l dzielącą P na dwa równoliczne (z dokładnością do
1) podzbiory:

P

L

- podzbiór punktów leżących na lewo od l,

P

R

- podzbiór punktów leżących na prawo od l.

Punkty znajdujące się na prostej l (o ile są takie) kwalifikujemy do tych
podzbiorów
w dowolny sposób.

2. { rekurencyjnie }
(i

1

, j

1

)  para punktów z P

L

o najmniejszej odległości;

(i

2

, j

2

)  para punktów z P

R

o najmniejszej odległości.

3.

Niech (i′, j′) będzie tą parą punktów znalezioną w kroku 2, dla

której odległość (oznaczmy ją przez d) jest mniejsza.
Sprawdzamy czy istnieje para punktów (t, s) odległych o mniej niż d
takich, że tP

L

i sP

R

. Jeśli istnieje, przekazujemy ją jako wynik procedury, w

przeciwnym razie jako wynik przekazujemy parę (i′, j′).

Znajdowanie pary najmniej odległych punktów c.d.

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 21

Znajdowanie pary najmniej odległych punktów c.d.

Realizacja kroku 3

Oznaczmy przez P

C

zbiór tych punktów z P, które leżą w odległości nie

większej niż d od prostej l. Niech Y′ oznacza tablicę Y, z której usunięto
wszystkie punkty spoza P

C

.

Wtedy:
Jeśli (t, s) jest parą punktów odległych o mniej niż d taką, że t P

L

i s

P

R

, to t i s należą do P

C

. Ponadto w tablicy Y‘ pomiędzy t a s leży nie

więcej niż 6 punktów.

W kroku 3 pary (t, s) należy szukać tylko w zaznaczonym pasie

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 22

Jeśli p ma być jednym z punktów pary (t, s), to drugi punkt musi
znajdować się w kwadracie B. Ponadto wszystkie punkty z Y ′ leżące
między t a s muszą leżeć w A lub w B.
W części A leżą tylko punkty z P

L

. Ponieważ każde dwa z nich odległe są

od siebie o co najmniej d, więc może ich tam znajdować się co najwyżej 4.
Z analogicznego powodu w części B może znajdować się nie więcej niż 4
punkty z P

R

. Tak więc w całym prostokącie znajduje się nie więcej niż 8

punktów.
Krok 3 sprowadza się więc do utworzenia tablicy Y ′, a następnie do
obliczenia odległości każdego punktu z Y ′ do co najwyżej siedmiu
punktów następujących po nim w tej tablicy.

Znajdowanie pary najmniej odległych punktów c.d.

background image

AiSD - Wykład 4 – Dziel i zwyciężaj

Slajd 23

Złożoność czasowa

Krok 1:

– Sortowanie - (n log n).

– Znalezienie prostej l i podział P na podzbiory - koszt
stały.

Krok 2:

– 2T(n/2)

Krok 3:

– Utworzenie Y ′ - (n).

– Szukanie pary (t, s) - (n).

Znajdowanie pary najmniej odległych punktów -

koszt

Zauważywszy, że sortowanie punktów w każdym wywołaniu
rekurencyjnym jest zbyteczne otrzymuje się złożoność:

T(n) = (n log n)


Document Outline


Wyszukiwarka

Podobne podstrony:
Wykład 04
Wyklad 04 2014 2015
biofizyka wyklad 04
Gwinty, wyklad 04 polaczenia srubowe CRC A717D1E6
Prawo konkurencji wykład 7 - 04.12, WPiA UŁ, Prawo ochrony konkurencji i konsumentów (T. Ławicki)
Młoda Polska WYKŁAD (04 06 2014)
Podstawy Systemów Okrętowych wykład 04 Przeciw Pożarnicze
msg ce wyklad 04
DSP Wyk%b3ad 04 UWM
Wykład 2.04, I rok, BPZ
Wykład 1 04.02, Studia, Współczesne systemy polityczne
Mechanika Budowli Sem[1][1] VI Wyklad 04
Kryptografia wyklad 04
wyklad  04 2010r
5 wyklad 04 2013
sedymentologia wykład" 04 2015
Pedagogika społeczna wykład 9 04 2011 wykł 6
wyklad 9 ) 04 2010
rmf wykład4 (6 04 2005) XY6MSZBEWOJL72NFRQR5SLWMHKPGZI75WO4S36Q

więcej podobnych podstron