• Nie Znaleziono Wyników

Algorytmy i Struktury Danych, Rozwiązania zadań z kolokwiów

N/A
N/A
Protected

Academic year: 2021

Share "Algorytmy i Struktury Danych, Rozwiązania zadań z kolokwiów"

Copied!
10
0
0

Pełen tekst

(1)

Algorytmy i Struktury Danych, Rozwiązania zadań z kolokwiów

2017-11

1 Klasówka 2007 (1), zadanie 1

Opracuj strukturę danych, która pozwala wykonywać następujące operacje:

• Ini(k):: inicjacja struktury danych i ustalenie długości krotek liczb całko- witych na k

• Insert(< a1, a2, . . . , ak>):: dodaje do struktury krotkę < a1, a2, . . . , ak>

• Min:: podaje najmniejszą leksykograficznie krotkę w strukturze

• ExtractMin:: usuwa najmniejszą leksykograficznie krotkę ze struktury W Twoim rozwiązaniu operacje Insert i ExtractMin powinny by wykonywane w czasie O(log n + k)

2 Klasówka 2007 (1), zadanie 1

Udowodnij, że jeśli algorytm sortujący tablicę A[1..n] porównuje i zamienia wy- łącznie elementy odległe co najwyżej o 2007 (tzn. jeśli porównuje A[i] z A[j], to |i − j| ≤ 2007), to jego pesymistyczny czas działania jest co najmniej kwa- dratowy.

Rozwiązanie: Pojedyncza zamiana usuwa O(1) inwersji więc dla ciągu od- wrotnie uporządkowanego (który ma O(n2) inwersji) algorytm wymaga czasu Ω(n2).

3 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- czu. Dzięki takiemu atrybutowi CountMin jest operacją trywialną. Możemy też aktualizować wartość tego atrybutu przy wszystkich operacjach kopcowych.

(2)

4 Klasówka 2009 (1), zadanie 1

Dana jest tablica n × n, n > 1, w której w każde pole wpisano liczbę całko- witą. Chcemy przejść z dolnego lewego rogu (z (1, 1)) do górnego prawego rogu (do (n, n) ) i wrócić, idąc w drodze z (1,1) zawsze w prawo lub w górę, a z powrotem - w lewo lub w dół. Z danego pola można przejść tylko na pola są- siednie (współrzędne różnią się o 1 na dokładnie jednej pozycji). Żadne pole nie może się pojawić na całej trasie (czyli tam i z powrotem) więcej niż raz, poza polem (1,1), które pojawia się na początku i na końcu trasy. Zaprojektuj algorytm znajdowania najtańszej trasy, czyli takiej, na której suma wartości pól jest najmniejsza. Rozwiązanie: dynamik po przekątnych

5 Klasówka 2010 (1), zadanie 2

Wykaż, że każdy algorytm znajdujący medianę w zbiorze 5-elementowym wy- kona w pesymistycznym przypadku co najmniej 5 porównań. Zaproponuj algo- rytm dokonujący tego za pomocą co najwyżej 6 porównań.

Rozwiązanie: Dolna granica: dzielimy wszystkie permutacje {1, . . . , 5} na klasy abstrakcji: (pozycja mediany, zbiór pozycji elementów mniejszych od mediany). Na przykład permutacja (5, 1, 4, 3, 2) należy do klasy abstrakcji (4, {2, 5}). Takich klas abstrakcji jest 5 · 42 = 30. Dowolne drzewo porównań które rozróżnia wszystkie klasy abstrakcji musi mieć wysokość h ≥ log230 > 4.

Zauważmy, że jeśli algorytm utożsamia jakieś dwie klasy abstrakcji to możemy skonstruować dane dla których udzieli nieprawidłowej odpowiedzi.

Algorytm wykonujący 6 porównań. Porównaj a i b, porównaj c i d, porównaj max(a, b) i max(c, d). Bez utraty ogólności a > b > c i d > c. Następnie:

Konfiguracja początkowa

a b

d c

e

d > e c

b a

d e d < e

c

b a

d e b < d

c

b

a d

e

b > d c

d b e

a

b > e c

b a

e d

b < e c

b

a e

d

(3)

6 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ć).

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:

(4)

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

7 Klasówka 2011 (1), zadanie 2

W tym zadaniu rozważamy n-elementowe ciągi k-uporządkowane (i-ty element ciągu jest nie większy od elementu i + k), 1 ≤ k ≤ n.

(5 pkt) Udowodnij, że każdy algorytm sortujący przez porównania wymaga w pesymistycznym przypadku Ω(n log k) porównań do posortowania n-elementowego ciągu k-uporządkowanego.

(5 pkt) Zaproponuj algorytm sortujący takie ciągi w czasie O(n log k).

Rozwiązanie: TODO

8 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: Podstawowa idea:

• dla każdego słowa wioblicz jego kod code(wi) = sorted(wi), gdzie sorted(w)

oznacza słowo w z uporządkowanymi niemalejącymi znakami (np. sorted(adbacab) = aaabbcd)

• posortuj słowa code(w1), . . . , code(wn) używając algorytmu z ćwiczeń (sor- towanie leksykograficzne słów różnej długości)

• usuń duplikaty z posortowanej listy.

Kroki drugi i trzeci w uczywisty sposób zajmą czas O(R + m) Niestety jeśli pierwszy krok tego algorytmu zaimplementujemy naiwnie, to może się okazać, że obliczenie code(wi) zajmie nam czas O(|wi| + m), co w sumie może dać O(R + nm).

Na szczęście możemy wygenerować kody słów w efektywniejszy sposób. Każdy znak z w1, . . . , wn zastępujemy przez trójkę (c, i, j) oznaczającą że wi[j] = c.

(5)

Sortujemy wszystkie trójki w jednym kroku. Teraz dzięki tej posortowanej li- ście mamy uporządkowane wszystkie litery z całego zbioru słów i możemy je kolejno dopisywać do kodów słów:

T = []

for w_i in w_1,...,w_n do for j in 1,...,|w_i| do

dodaj (w_i[j], i, j) do T posortuj T

for i in 1,...,n do code[w_i] = ""

for (c, i, j) in T do code[w_i] += c

Dzięki “zbiorczemu” sortowaniu listy T udało się obliczyć kody wszystkich słów w w czasie O(R + m).

Przykład:

w_1 = aba w_2 = ba w_3 = caa w_4 = ab T = [

(a, 1, 1), (b, 1, 2), (a, 1, 3), (b, 2, 1), (a, 2, 2), (c, 3, 1), (a, 3, 2), (a, 3, 3), (a, 4, 1), (b, 4, 2) ]

posortowane T = [ (a, 1, 1), (a, 1, 3), (a, 2, 2), (a, 3, 2), (a, 3, 3), (a, 4, 1), (b, 1, 2), (b, 2, 1), (b, 4, 2), (c, 3, 1) ]

(6)

code(w_1) = aab code(w_2) = ab code(w_3) = aac code(w_4) = ab

9 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 1: 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 2: Unpack(A)

if |A| > 2 then

l = b|A|/4c; r = d|A|/4e ;

// zamień ciąg 0|A|/21|A|/2 na 0l1l0r1r Exchange(A[(l + 1)..2l], A[(2l + 1)..(2l + r)]) Unpack(A[1..2l])

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

10 Klasówka 2013 (1), zadanie 1

Zaprojektuj optymalny algorytm pod względem pesymistycznej liczby porów- nań, który znajduje dwa środkowe elementy w zbiorze czterech elementów. Do- wiedź poprawności swojego rozwiązania.

Rozwiązanie: TODO

11 Klasówka 2013 (1), zadanie 2

Drzewem klasówkowym nazywamy pełne drzewo binarne, w którym klucze są rozmieszczone zgodnie z następującą regułą: dla każdego węzła x najmniejszy klucz w poddrzewie o korzeniu x znajduje się w jego lewym podrzewie.

Zaproponuj implementację drzewa klasówkowego w sposób, który umożliwia wydajne wykonywanie operacji kolejki priorytetowej:

• Ini:: mając dane n = 2k− 1 kluczy zbuduj n-węzłowe drzewo klasówkowe

(7)

• Min:: podaj wartość najmniejszego klucza w drzewie

• ChangeKey(x,k):: zmień wartość klucza we wskazanym węźle x na k Uzasadnij poprawność swoich rozwiązań oraz dokonaj analizy ich złożności ob- liczeniowej.

Rozwiązanie: Przykład drzewa klasówkowego:

5

/ \

3 8

/ \ / \

1 5 2 7

Wzbogacamy węzły v o dodatkowy atrybut min, który zawiera najmniejszy element z poddrzewa (łącznie z wartością v.x). Formuła na aktualizację tego atrybutu:

v.min := min(v.lef t.min, v.right.min, v.x)

Tak jak w kopcu jesteśmy w stanie zdefiniować operację DownHeap(v):

• jeśli v jest liściem to nic nie rób,

• jeśli v.lef t.min > v.right.min -> swap(v.lef t, v.right)

• jeśli v.x < v.lef t.min, v.right.min -> zamień v.x i v.lef t.x, zaktualizuj v.min i wykonaj DownHeap(v.lef t)

Analogicznie U pHeap(v):

• jeśli v jest korzeniem to nic nie rób,

• niech p = parent(v),

• zaktualizuj p.min,

• jeśli p.lef t.min > p.right.min -> swap(p.lef t, p.right)

• wykonaj U pHeap(p) Implementacja operacji:

• Ini:: utwórz drzewo a następnie wykonaj DownHeap dla wszystkich wę- złów idąc od warstwy k to 1 (tak jak w liniowym algorytmie tworzenia kopca)

• Min:: zwróć root.min

• ChangeKey:: zmień klucz i wykonaj DownHeap(v) i U pHeap(v)

(8)

12 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ść czasowa: O(P |Li|). Złożoność pamięciowa: O(k) (na potrzeby uporządkowania list, nie potrzebujemy dodatkowej pamięci na scalanie bo operujemy na listach, które można scalać w pamięci O(1)).

13 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:

Algorithm 3: 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.

(9)

14 Klasówka 2015 (1), zadanie 3

Rozważamy dynamicznie zmieniający się ciąg A =< a1, a2, . . . , an >, parami różnych n liczb całkowitych. Na ciągu A dozwolona jest jedyna operacja N aP oczatek(i), 1 ≤ i ≤ n, która przesuwa element ai na początek A.

Przykład: Dla A =< 4, 1, 3, 5, 2 >, po wykonaniu N aP oczatek(3) dostajemy A =< 3, 4, 1, 5, 2 >.

Interesuje nas ciąg operacji NaPoczątek o minimalnej długości, których wy- konanie posortuje A. Nazwijmy go minimalnym ciągiem sortującym.

a) [3 punkty] Zaprojektuj algorytm, który w czasie O(n) wyznacza pierwszy element minimalnego ciągu sortującego.

b) [2 punkty] Zaprojektuj efektywny algorytm wyznaczający cały minimalny ciąg sortujący.

c) [4 punkty] Udowodnij poprawność swoich rozwiązań.

Dokonaj analizy złożoności czasowej zaproponowanych algorytmów.

Rozwiązanie: Zauważmy, że jeśli algorytm sortujący wykona przeniesienie elementu ai = x to w kolejnych ruchach musi również przenieść wszystkie ele- menty o wartościach 1, . . . , x − 1. Dodatkowo optymalny algorytm sortujący nie przenosi żadnego elementu więcej niż 1 raz.

Podpunkt (a):

Należy wyznaczyć, minimalne k ≤ n, takie, że k + 1, k + 2, . . . , n jest podciągiem A. Można to zrobić w czasie O(n) analizując ciąg A od prawej strony i szukając kolejno n, n − 1, itd. Pierwsza operacja to N aP oczatek(A−1(k)) (przeniesienie elementu o wartości k).

Podpunkt (b):

Kolejne operacje to N aP oczatek(A−1(k − 1)), N aP oczatek(A−1(k − 2)), . . . , N aP oczatek(A−1(1)).

Niestety żeby efektywnie wykonywać operację A1 konieczna jest struktura danych, która pozywala na:

• znalezienie indeksu elementu o wartości x

• usunięcia elementu o wartości x z ciągu

• dodanie elementu o wartości x na początek ciągu

Przy pomocy drzew zrównoważonych, każdą z tych operacji można wykonać w czasie O(log n). Co daje algorytm o złożoności (n log n).

Przykład:

A = 4 1 5 6 3 7 2

k=3, ponieważ [4,5,6,7] jest podciągiem A NaPoczatek(A^{-1}(3)=5)

A_1 = 3 4 1 5 6 7 2 NaPoczatek(A^{-1}(2)=7) A_2 = 2 3 4 1 5 6 7 NaPoczatek(A^{-1}(1)=4) A_3 = 1 2 3 4 5 6 7

(10)

15 Klasówka 2016 (1), zadanie 2

Niech n będzie dodatnią liczbą całkowitą. Dla dodatniej liczby całkowitej k powiemy, że ciąg liczb a[1], . . . , a[n] jest k-dobry, jeśli każda inwersja (i, j), 1 ≤ i < j ≤ n, spełnia j ≤ i + k.

a) [8 punktów] zaproponuj asymptotycznie optymalny ze względu na porów- nania algorytm sortujący ciągi k-dobre. Uzasadnij asymptotyczną opty- malność swojego algorytmu. Uwaga: w tym zadaniu argumentami funkcji złożoności są k i n.

b) [5 punktów] zaproponuj efektywny czasowo i pamięciowo algorytm, który sprawdza czy ciąg liczb a[1], . . . , a[n] dla zadanej liczby całkowitej k, jest k-dobry. Uzasadnij poprawność algorytmu i dokonaj analizy czasowej i pamięciowej

Rozwiązanie: (a) Dowolny algorytm sortujący oparty o porówniania musi wykonać Ω(n log k) porównań: istnieje co najmniej (k!)n/k różnych permutacji n-elementowych, które są k-dobre. Stąd algorytm sortujący musi wykonać co najmniej log((k!)n/k) porównań, czyli Ω(n/k · k log k) = Ω(n log k). Konstrukcja tej rodziny permutacji: podziel liczby na bloki B1 = 1..k, B2 = k + 1..2k, itd. permutacja otrzymana z dowolnego przemieszania bloków p(B1) + p(B2) + p(B3) . . . jest k-dobra.

Algorytm: sortuj kolejno bloki długości 2k zaczynające się na pozycjach 1, k + 1, 2k + 1, . . ..

(b) Niech pmax[i] oznacza max a[1..i] (maksymalne wartości dla wszystkich prefiksów tablicy). Tablica a jest k-dobra, jeśli

pmax[i − k] ≤ a[j] : k ≤ j ≤ n

Cytaty

Powiązane dokumenty

Zadanie Do zbioru reprezentowanego przez drzewo D dołączyć element e, o ile nie należy on jeszcze do etykiet drzewa D.... Zastosowanie: wyszukiwanie

(3) Jeżeli tak otrzymane drzewo nie jest częściowo uporządkowane, to przechodząc wzdłuż drogi od liścia x do korzenia, poprawić etykiety zamieniając etykietę ojca z

Jeśli element e należy do kolejki q, to po skończonej liczbie usunięć kolejnych elementów minimalnych.. dotrę do tego

takie drzewo &lt;V, T&gt; rozpinające grafu G, że suma kosztów jego krawędzi  eT c (e) jest najmniejsza.. Mirkowska, ASD_12 Algorytmy na

Niech będzie tekst 100000 znakowy, w którym występują tylko litery a,b,c,d,e,f i a-45tys razy, b-13tys., c-12tys.,.. d-16tys., e -

Powiemy, że problem jest rozstrzygalny, jeśli istnieje algorytm, który dla dowolnych danych x po skończonej liczbie kroków daje rozwiązanie problemu. W przeciwnym

Dowód przez indukcję ze względu na liczbę wywołań rekurencyjnych funkcji min_max.. Dla jednego tylko wywołania

Problem Dany jest ciąg rosnący e[1],..,e[n] oraz element x pewnej przestrzeni liniowo uporządkowanej &lt;E, &gt;. Następnie porównujemy x z kolejnymi elementami ciągu