• Nie Znaleziono Wyników

1 Klasówka 2014 (1), zadanie 3

N/A
N/A
Protected

Academic year: 2021

Share "1 Klasówka 2014 (1), zadanie 3"

Copied!
5
0
0

Pełen tekst

(1)

Algorytmy i Struktury Danych, 7. ćwiczenia

2015-11-13

Spis treści

1 Klasówka 2014 (1), zadanie 3 1

2 Klasówka 2013 (1), zadanie 3 2

3 Klasówka 2012 (1), zadanie 3 3

4 Klasówka 2012 (1), zadanie 2 3

5 Klasówka 2011 (1), zadanie 1 3

6 Klasówka 2008 (1), zadanie 2 4

7 Scalanie w miejscu dla ciągów długości √

n i n −√

n 5

8 Scalanie w miejscu 5

1 Klasówka 2014 (1), zadanie 3

Dane są liczby całkowite dodatnie n, k, przy czym k ≤p(n). W tablicy a[1..n]

zapisano n liczb całkowitych o co najmniej k różnych wartościach. Należy zapro- jektować algorytm, który stabilnie i w miejscu przemieści k parami różnych liczb na początek tablicy a i uporządkuje je rosnąco. Stabilność w tym przypadku oznacza, że kolejność występowania w tablicy liczb o tych samych wartościach zostaje zachowana. Twój algorytm powinien działać w czasie O(n log n).

Rozwiązanie:

(2)

Algorithm 1: Solution1(A, k)

Niech B oznacza blok A w którym będziemy gromadzić posortowane rosnąco różne elementy z A

Początkowo B jest pusty blokiem na samym początku A foreach i ∈ 1, . . . , n do

if binarySearch(A[i], B) then

// element A[i] jest już znany więc go ignorujemy else

// element A[i] jest nowy i chcemy go dodać do B

niech X oznacza blok zaczynający się za B i kończący na A[i − 1]

Exchange(B, X) dodaj A[i] do B if |B| ≥ k then break przenieś blok B na początek A

Analiza: Koszt O(n log n) ze względu na wykonywane O(n) razy wyszuki- wanie binarne. Pozostałe operacje zajmują O(n) czasu:

• koszt dodawania nowych elementów to O(k2) czyli O(√

n2) = O(n)s,

• koszt wszystkich operacji Exchange to O(n) ponieważ Pp

j=1|Xj| ≤ n (zauważmy, że wszystkie zbiory Xj są rozłączne), orazPp

j=1|Bj| ≤ k2≤ n.

Alternatywne rozwiązanie (ale wymagające implementacji algorytmy scalania ciągów w miejscu ale niekoniecznie stabilnego).

Algorithm 2: Solution2(A, k) (Bl, Xl)=Solution2(A[1..n/2], k) (Br, Xr)=Solution2(A[n/2 + 1..n], k) if |Bl| ≥ k then

return (Bl, Xl+ Br+ Xr)

niech α = set(Br) − set(Bl), β = set(Br) ∩ set(Bl)

podziel blok Br na α (uporządkowane rosnąco) i β (dowolnie przemieszane)

Exchange(Xl, α)

B:=Merge(Bl, α) to musi być algorytm w miejscu ale niekoniecznie stabilny

return (B, Xl+ β + Xr)

2 Klasówka 2013 (1), zadanie 3

Danych jest k uporządkowanych list o długościach będących parami różnymi potęgami dwójki. Zaproponuj wydajny algorytm scalenia tych list w jedną listę uporządkowaną. Uzasadnij poprawność swojego algorytmu i dokonaj analizy jego złożoności obliczeniowej ze względu na liczbę porównań wykonywanych podczas scalania.

Rozwiązanie: Uporządkuj listy rosnąco według długości i scalaj od najkrótszej do najdłuższej. Złożoność O(P |Li|).

(3)

3 Klasówka 2012 (1), zadanie 3

Dana jest 2n-elementowa tablica zawierająca n zer i n jedynek. Chcemy ją uporządkować tak, żeby zera i jedynki były ułożone na przemian, począwszy od zera, tj. 010101... Zaproponuj efektywny algorytm, który wykona to w miejscu i stabilnie (tj. kolejność zer i kolejność jedynek z wejścia muszą być zachowane).

Rozwiązanie: Posortuj stabilnie (ala MergeSort) a następnie rekurencyjnie poprzeplataj.

Algorithm 3: Sort(A) if |A| ≥ 2 then

(Zl, Ol)=Sort(A[1..n/2]) (Zr, Or)=Sort(A[n/2 + 1..n]) Exchange(Ol, Zr)

return (Zl+ Zr, Ol+ Or) else

return (A, ∅) (if A=[0]) or (∅, A) otherwise

Algorithm 4: Unpack(A) if |A| ≥ 2 then

Unpack(A[1..n/2]) Unpack(A[n/2 + 1..n])

Exchange(A[n/4..n/2], A[n/2 + 1..3n/4])

4 Klasówka 2012 (1), zadanie 2

Powiemy, że dwa napisy są podobne wtedy i tylko wtedy, gdy zawierają jed- nakowe liczby wystąpień tych samych znaków. Danych jest n napisów nad alfabetem m-znakowym {1, 2, . . . , m}. Zaproponuj algorytm, który stwierdza, ile jest wśród nich różnych klas napisów podobnych. Twój algorytm powinien działać w czasie O(R + m), gdzie R jest sumą długości wszystkich napisów.

Rozwiązanie: Dla słów w1, . . . , wm możemy wygenerować w czasie O(R + m) zbiór trójek (c, i, j) oznaczających że słowo wi[j] = c. Sortujemy trójki i dzięki temu możemy wygenerować kody code(wi) = sorted(wi). Teraz musimy tylko sprawdzić ile jest różnych słów w zbiorze {code(wi) : 1 ≤ i ≤ n}.

5 Klasówka 2011 (1), zadanie 1

Danych jest n słów o takiej samej długości k, zbudowanych ze znaków n-elementowego, uporządkowanego alfabetu. Rozmiarem zadania w tym przypadku jest R = nk.

• Zaproponuj algorytm, który dla danego i, 1 ≤ i ≤ k, obliczy w czasie O(R) liczbę wszystkich par słów, które różnią się tylko na i-tej pozycji.

• Zaproponuj algorytm, który obliczy w czasie O(R) liczbę wszystkich par słów, które różnią się tylko na dokładnie jednej pozycji.

Rozwiązanie: Zakładamy że wszystkie słowa na wejściu są różne (możemy to łatwo sprawdzić).

(4)

Dla dowolnego i, j przez pref (i, j) oznaczamy kod prefiksu słowa widługości j, chcemy żeby kody były liczbami z zakresu 1..n takimi, że, wi[1..j] = wq[1..j]

wtw pref (i, j) = pref (q, j) (czyli mogą służyć do porównywania prefiksów usta- lonej długości)

Analogicznie definiujemy dla sufiksów: suf (i, j).

Rozwiązujemy w czasie O(n) każdy problem z osobna dla j ∈ 1..k (w tym kroku będziemy liczyć pary słów które różnią się dokładnie na j-tej pozycji)

P = ∅

for i:=1..n do

P += (pref (i, j − 1), suf (i, k − j), i) (czyli zapisujemy kod słowa bez j-tego znaku)

posortuj leksykograficznie trójki z P ile:=0

foreach grupy G trójek o tych samych wartościach pierwszych dwóch elementów do

// dowolna para słów z G różni się jedynie na j-tej pozycji ile+ = |G| ∗ (|G| − 1)/2

Warto zauważyć, że jeśli jakieś dwa słowa różnią się na dokładnie jednej pozycji to istnieje tylko jedna wartość j w której zostaną zliczone

Ponieważ każda faza zajmuje czas O(n) i faz jest k więc cały algorytm zaj- muje O(nk).

Pozostaje jeszcze powiedzieć jak obliczyć pref/suf - robimy to podobnie jak w izomorfizmie drzew, trzeba po prostu kompresować kody:

for i:=1 to n do pref (i, 1) = wi[1]

for j:=2 to k do P = ∅

for i:=1 to n do

P += (pref (i, j − 1), wi[j], i) posortuj leksykograficznie trójki z P

zgrupuj trójki o tych samych wartościach pierwszych dwóch elementów w G1, G2, ..Gp

for t:=1 to p do

foreach (p, q, i) ∈ G do pref (i, j) = t

6 Klasówka 2008 (1), zadanie 2

Zaproponuj wzbogacenie kopca zupełnego w taki sposób, żeby efektywnie w czasie zamortyzowanym wykonywane były operacje: Min, DeleteMin, Insert, CountMin. Ostatnia operacja polega na podaniu aktualnej liczby elementów w kopcu o wartości równej Min. Przeprowadź analizę kosztu zamortyzowanego wykonania poszczególnych operacji.

Rozwiązanie: Wzbogacamy węzły kopca o atrybut countEq oznaczającą liczbę węzłów w poddrzewie zawierających identyczną wartość co ten zapisany w klu-

(5)

czu. Dzięki takiemu atrybutowi CountMin jest operacją trywialną. Możemy też aktualizować wartość tego atrybutu przy wszystkich operacjach kopcowych.

7 Scalanie w miejscu dla ciągów długości √ n i n − √

n

Algorithm 5: Merge(A)

Dana jest tablica A zawierająca dwa uporządkowane rosnąco ciągi:

1..n −√

n i n −√

n + 1..n.

Posortuj (używając alg. insertion sort) ciąg n − 2√

n + 1..n Scal ciąg 1..n − 2√

n i n − 2√

n + 1..n −√

n używając obszaru n −√

n + 1..n jako bufor

Posortuj (używając alg. insertion sort) ciąg n −√

n + 1..n

8 Scalanie w miejscu

Knuth, Tom III, strona 698.

• podziel tablicę na bloki rozmiaru d√

ne, — Z1, Z2, . . ., Zm+2, (blok Zm+2

może być mniejszy,

• zamień blok leżący na połączeniu dwóch ciągów, z blokiem Zm+1, teraz każdy z bloków Z1, . . ., Zmjest uporządkowany,

• posortuj używając selection–sort bloki, wg. pierwszego elementu z bloków (jeśli dwa bloki mają ten sam element początkowy, to porównaj elementy końcowe)

• scal Z1, . . ., Zm używając Zm+1 jako bufora pomocniczego, Algorithm 6: Z-Merge(Z)

foreach i ∈ 1, . . . , m − 1 do SimpleMerge(Zi,Zi+1,Zm+1)

(należy jeszcze pokazać, że taka procedura daje dobre uporządkowanie) — wskazówka: przed tym krokiem każdy element jest w inwersji z co najwyżej p(n) innymi elementami bloków Z1, .., Zm+1

• dzielimy tablicę na trzy części: A, B, C, |B| = |C| = 2d√ ne

• posortuj ostatnie 4 · d√

ne elementów (bloki B, C) używając InsertionSort (w rezultacie w bloku C znajdują się największe elementy w tablicy)

• scal bloki A i B używając C jako bufora

• posortuj blok C używając InsertionSort

Ćwiczenie: dlaczego używając selection-sort trzeba uwzględniać początki i końce bloków? Rozwiązanie: np. dla ciągów (111,123),(111,145) (rozmiar bloku 3), sortując jedynie po początkach moglibyśmy otrzymać: (123,145,111,111), który przy scalaniu metodą opisaną w algorytmie nie da uporządkowanego ciągu.

Cytaty

Powiązane dokumenty

1 Dwukrotne zwiekszenie rozdzielczosci pikselowej obrazu (w poziomie i pionie) powoduje dwukrotne zwiekszenie rozmariow pamieci potrzebnej do jego przechowywania N?.

Ilość Polaków posiadających kartę kredytową zmienną losową o rozkładzie

Warto zwrócid uwagę na fakt, że typ string jest niczym innym jak tablicą składającą się z określonej liczby elementów typu CHAR. Możliwe jest dośd ciekawe uzycie zmiennej

Teraz wystarczy zauważyć, że macierz odwrotna do górnej (dolnej) trójkątnej jest też górną (dolną) trójkątną, a jeśli do- datkowo na głównej przekątnej miała jedynki,

(d) Ile jest takich, w których »adne dwie litery N nie s¡ obok siebie?. Odpowied¹

Ile różnych deserów może z tego sporządzić ekspedientka, jeśli w pucharku mieści się nie więcej niż 5 kulek lodów, a pusty pucharek nie jest deserem..

Uwaga, dwa sposoby usadzenia uważamy za takie same, jeśli w obu sposobach każda z osób ma tych samych sąsiadów zarówno po lewej, jak i prawej stronie..

Dowolne drzewo porównań które rozróżnia wszystkie klasy abstrakcji musi mieć wysokość h ≥ log 2 30 > 4.. Zauważmy, że jeśli algorytm utożsamia jakieś dwie klasy