ASD Ćwiczenia 13: Różnice pomiędzy wersjami
m Zastępowanie tekstu – „<math> ” na „<math>” |
|||
(Nie pokazano 25 wersji utworzonych przez 4 użytkowników) | |||
Linia 1: | Linia 1: | ||
=='''Zadanie 1''' == | =='''Zadanie 1''' == | ||
Uzasadnij poprawność algorytmu obliczającego długość najkrótszego słowa pokrywającego dany tekst. | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"> | ||
Rozwiązanie | Rozwiązanie | ||
Linia 7: | Linia 7: | ||
<div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible-content" style="display:none"> | ||
Niech <math>S[i]</math> | Niech <math>S[i]</math> | ||
będzie rozmiarem minimalnego | będzie rozmiarem minimalnego pokrywającego słowa dla prefiksu <math>x[1..i]</math>. Poprawność wynika z następującego | ||
faktu: \ <math>S[i]=i \ \ | faktu: \ <math>S[i]=i \ \text{lub}\ S[i]=S[P[i]]</math>. | ||
</div> | </div> | ||
</div> | </div> | ||
Linia 16: | Linia 16: | ||
=='''Zadanie 2''' == | =='''Zadanie 2''' == | ||
Udowodnij, że w wersji on-line algorytmu KMP mamy <math>delay = O(\log m)</math> | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"> | ||
Linia 24: | Linia 24: | ||
Wystarczy wykazać, że | Wystarczy wykazać, że | ||
<math> P'[i]=j,\ P'[j]=k>0\ \Rightarrow \ i\ge k+j </math> | <math>P'[i]=j,\ P'[j]=k>0\ \Rightarrow \ i\ge k+j</math> | ||
Fakt ten wynika z lematu o okresowości i z definicji tablicy P'. | Fakt ten wynika z lematu o okresowości i z definicji tablicy P'. | ||
</div> | </div> | ||
Linia 35: | Linia 34: | ||
=='''Zadanie 3''' == | =='''Zadanie 3''' == | ||
Udowodnij, że w wersji on-line algorytmu KMP mamy <math>delay = \Omega(\log m)</math> | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"> | ||
Linia 42: | Linia 41: | ||
<div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible-content" style="display:none"> | ||
Słowa Fibonacciego definiujemy następująco: | Słowa Fibonacciego definiujemy następująco: | ||
<center><math>F_0=a,\ F_1=ab,\ F_{n+1} | <center><math>F_0=a,\ F_1=ab,\ F_{n+1}= F_n\cdot F_{n-1}</math></center> | ||
Na przykład: <math>F_3=abaab,\ F_4=abaababa,\ F_5=abaababaabaab | Na przykład: <math>F_3=abaab,\ F_4=abaababa,\ F_5=abaababaabaab</math>. | ||
Niech <math>F'_n</math> oznacza słowo Fibonacciego z obciętymi ostatnimi dwoma symbolami. Jeśli jako wzorzec | Niech <math>F'_n</math> oznacza słowo Fibonacciego z obciętymi ostatnimi dwoma symbolami. Jeśli jako wzorzec weźmiemy słowo Fibonacciego <math>F_n</math>, a jako tekst słowo <math>F'_ncc</math> to przy wczytywaniu <math>|F_n-1|</math>-ego symbolu algorytm ma opóżnienie logarytmiczne, iterujemy <math>\Omega(\log n)</math> razy operację: <math>j:=P'[j]</math>. | ||
</div> | </div> | ||
</div> | </div> | ||
=='''Zadanie 4''' == | =='''Zadanie 4''' == | ||
Mamy zbiór słów, każde długości dwa, obliczyć długość minimalnego tekstu który zawiera wszystkie słowa. | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"> | ||
Linia 61: | Linia 60: | ||
<div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible-content" style="display:none"> | ||
Weźmy graf, którego węzłami są litery, a słowa wejściowe odpowiadają krawędziom. | |||
Wystarczy znalezć minimalną liczbę krawędzi, które trzeba dołożyć do grafu, by miał on | |||
ścieżkę Eulera. | |||
'''Dygresja''' Zadanie to było na Olimpiadzie Informatycznej pod nazwą ''pierwotek abstrakcyjny''. | |||
Ciekawe jest to, że problem robi się NP-zupełny, gdy wszytkie słowa wejściowe mają długość 3. | |||
</div> | </div> | ||
</div> | </div> | ||
=='''Zadanie 5''' == | |||
Udowodnij następującą ciekawą własność kombinatoryczną okresowości w tekstach. Niech <math>nwd(p,q)</math> oznacza najmniejszy wspólny dzielnik p,q. | |||
{{lemat|[Lemat o okresowości]|lemat_o_okresowosci| | |||
Jeśli x ma okresy p, q oraz <math>p+q \le |x|</math>, to <math>nwd(p,q)</math> jest również okresem x. | |||
}} | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"> | ||
Rozwiązanie | Rozwiązanie | ||
<div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible-content" style="display:none"> | ||
Lemat ten wynika z poprawności algorytmu Euklidesa z odejmowaniem, który oblicza nwd(p,q). Zauważmy, że jeśli <math>p>q</math> są okresami, to p-q też jest okresem. | |||
</div> | </div> | ||
</div> | </div> | ||
=='''Zadanie 6''' == | =='''Zadanie 6''' == | ||
Lemat o okresowości można wzmocnić, osłabiając założenia. Udowodnij następujący lemat. | |||
{{lemat|[Silny lemat o okresowości]|silny_lemat_o_okresowosci| | |||
Jeśli x ma okresy p, q oraz <math>p+q \le |x|+nwd(p,q)</math>, to <math>nwd(p,q)</math> jest również okresem x. | |||
}} | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"> | ||
Linia 98: | Linia 103: | ||
<div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible-content" style="display:none"> | ||
Indukcja ze względu na p+q. | |||
</div> | </div> | ||
</div> | </div> | ||
=='''Zadanie 7''' == | |||
Udowdnij poprawność algorytmu KMP realtime | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
Rozwiązanie | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Problem jaki musimy rozwiązać to właściwość algorytmu, którą nazwiemy | |||
''opóżnieniem''. Polega ona na tym, że w danym kroku algorytm może wciąż | |||
jeszcze rozważać właściwy prefiks aktualnego słowa i nie dotrzeć w ogóle | |||
do rozważenia bieżącej litery. Pokażemy jednak, że w momencie, kiedy nastąpi | |||
wystąpienie wzorca, kolejka zostanie opróżniona, co wystarczy do | |||
dowodu poprawności algorytmu. | |||
Dowód przeprowadzimy nie wprost - załóżmy, że w tym kroku kolejka | |||
się nie opróżni i że jest to pierwsze wystąpienie wzorca, którego algorytm nie | |||
zdąża wyśledzić. Zacznijmy rozważanie działania algorytmu od ostatniego | |||
miejsca wcześniejszego od bieżącego, w którym kolejka się opróżnia. | |||
W tym momencie zachodzi <math>j<m</math> (nawet jeżeli w owym kroku było wystąpienie | |||
wzorca w tekście, to ten warunek i tak będzie po tym kroku spełniony) | |||
oraz <math>|Kolejka|=0</math>. Pokażemy, że odtąd | |||
aż do miejsca wystąpienia wzorca zachodzić będzie niezmiennik | |||
<center> <math>|Kolejka|<m-j</math>.<br></center> | |||
Faktycznie, zastanówmy się co się może wydarzyć w dowolnym, kolejnym kroku algorytmu, | |||
a co może zmienić wartość zmiennej <math>j</math>: | |||
Może być dwukrotnie wywołana instrukcja <math>j:=P[j]</math>. | |||
Wówczas <math>|Kolejka|</math> wzrasta o <math>1</math>, <math>m-j</math> wzrasta co najmniej o <math>2</math>, | |||
czyli niezmiennik dalej zachodzi. | |||
Moze być raz wywołana instrukcja <math>j:=P[j]</math>, a raz <math>j:=j+1</math> (w jakiejkolwiek | |||
kolejności). Wówczas <math>|Kolejka|</math> się nie zmienia, <math>m-j</math> pozostaje bez zmian | |||
lub wzrasta, co nie zaburza niezmiennika. | |||
Mogą nastąpić dwie instrukcje powiększające <math>j</math> o <math>1</math>. | |||
Wówczas <math>|Kolejka|</math> maleje o <math>2</math>, <math>m-j</math> także maleje o <math>2</math>, zatem niezmiennik pozostaje zachowany. | |||
Kolejka \textit{nie} może się opróżnić, gdyż zakładamy, że to nie nastąpi | |||
przed aktualnie rozważanym wystąpieniem wzorca. Instrukcja <math>j:=P[m]</math> również | |||
nie może wystąpić, ponieważ oznaczałoby to wcześniejsze od rozważanego | |||
niezauważone przez algorytm wystąpienie wzorca w tekście. | |||
Zatem niezmiennik jest zachowany od ostatniego momentu opróżnienia kolejki | |||
do momentu niezauważonego wystąpienia wzorca. W chwili przetworzenia literki, | |||
która powoduje wystąpienie zachodzi <math>j=m</math>, czyli na mocy pokazanego niezmiennika | |||
<math>|Kolejka|<m-m=0</math>, <math>|Kolejka|<0</math>. To z kolei daje żądaną sprzeczność. | |||
''(Rozwiązanie opracował Jakub Radoszewski)'' | |||
</div> | |||
</div> | |||
=='''Zadanie 8''' == | |||
Przprowadź dokładny dowód tego, że algorytm Oszczędny KMP wykonuje co najwyżej 3/2 n porównań | |||
(schemat dowodu był już opisany w odpowiednim module) | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"> | ||
Rozwiązanie | Rozwiązanie | ||
<div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible-content" style="display:none"> | ||
<br> | |||
</div> | By wykazać, że algorytm Oszczędny-MP wykonuje co najwyżej <math>\frac{3}{2}n</math> | ||
porównań, pogrupujemy te porównania w dwie szufladki: <math>A</math> i <math>B</math> . Pokażemy, że | |||
w szufladce <math>A</math> będzie co najwyżej <math>n</math> porównań, a w szufladce <math>B</math> co najwyżej <math>\frac{n}{2}</math> porównań. Do szufladki <math>A</math> wrzucamy: | |||
<br> | |||
Wszystkie udane porównania dokonane w trakcie szukania wzorca <math>x'</math> . | |||
<br> | |||
Wszystkie nieudane porównania pierwszej litery wzorca <math>x'</math> (czyli litery <math>b</math> ), dokonane w trakcie szukania wzorca <math>x'</math> . | |||
<br> Wszystkie porównania początkowych liter <math>a</math> , za wyjątkiem porównań na tych pozycjach, gdzie wcześniej szukaliśmy litery <math>b</math> (pierwszej litery wzorca <math>x'</math>) i nie znaleźliśmy jej. | |||
<br> | |||
Do szufladki <math>B</math> wrzucamy wszystkie pozostałe porównania, czyli: | |||
<br> | |||
Wszystkie nieudane porównania dokonane w trakcie szukania wzorca <math>x'</math> , za wyjątkiem nieudanych porównań pierwszej litery; są to nieudane porównania dokonywane w momencie, gdy znaleźliśmy już jakiś niepusty prefiks <math>x'</math> . | |||
<br> Porównania początkowych liter <math>a</math> na tych pozycjach, gdzie wcześniej szukaliśmy litery <math>b</math> i nie znaleźliśmy jej. | |||
<br> | |||
Zauważmy, że w algorytmie MP pozycje tekstu, na których nigdy nie było żadnego udanego porównania to dokładnie te pozycje, na których nie udało się znaleźć pierwszej litery wzorca (lub pozycja jest pod sam koniec tekstu i nie ma już szans na znalezienie wzorca, algorytm już się zakończył). Dodatkowo, zarówno algorytm MP jak i algorytm Oszczędny-MP ma taką właściwość, że jeśli na pewnej pozycji tekstu było udane porównanie, to ta pozycja tekstu już nigdy nie będzie porównywana (o niej ,,wiemy już wszystko''). W związku z tym każde porównanie z szufladki <math>A</math> wykonuje się na innej literze tekstu, czyli tych porównań jest co najwyżej <math>n</math> . | |||
Spójrzmy teraz, jak zmienia się wskaźnik, na jakiej pozycji szukamy teraz wzorca <math>x</math> . Zauważmy, że prefikso-sufiks słowa <math>x[1\ldots s]</math> dla <math>s > k</math> jest długości co najwyżej <math>s - k - 1</math> (litery <math>a</math> tego prefikso-sufiksu muszą się zaczynać za literą <math>b</math> na pozycji <math>k+1</math> ). W związku z tym w momencie nieudanego porównania, które wystąpiło gdy znaleziony już został niepusty prefiks słowa <math>x'</math> , wskaźnik ,,gdzie teraz szukamy'' przesuwa się o conajmniej <math>k+1</math> . Tak też jest, gdy znajdziemy całe słowo <math>x'</math> ( przesuwamy się do prefikso-sufiksu słowa <math>x</math>) . Dodatkowo, każde nieudane porównanie litery <math>b</math> z pozycji <math>k+1</math> w słowie <math>x</math> przesuwa wskaźnik o jeden. | |||
W związku z tym: | |||
<br> | |||
Porównania z szufladki <math>B</math> , podpunkt <math>1</math> przesuwają wskaźnik o conajmniej | |||
<math>k+1 \geq 2</math> . | |||
<br> | |||
Po co najwyżej <math>k</math> porównaniach z szufladki <math>B</math> , podpunkt <math>2</math> wskaźnik | |||
przesunie się o conajmniej <math>k+1</math> . Dodatkowo, każde takie porównanie oznacza, że wcześniej na tym miejscu było nieudane porównanie litery <math>b</math> . Wliczając przesunięcia pochodzące od tych porównań otrzymujemy, że | |||
wskaźnik przesunął się o conajmniej <math>k+1+L \geq 2L</math> , gdzie <math>L</math> to liczba takich porównań liter <math>a</math> w jednej próbie znalezienia wzorca <math>x</math> . | |||
<br> | |||
Czyli każde porównanie z szufladki <math>B</math> przesuwa aktualny wskaźnik (''gdzie teraz szukamy'') o conajmniej <math>2</math> , czyli tych porównań jest nie więcej niż <math>\frac{n}{2}</math> . | |||
''(Rozwiązanie opracował Marcin Pilipczuk)'' | |||
</div> | |||
</div> | </div> | ||
=='''Zadanie 9''' == | |||
Słowa cykliczne (de Bruijna): | |||
Słowo binarne w długości dokładnie <math>2^n</math> nazwiemy cyklicznym (słowem de Bruijna, który to wymyślił) rzędu n gdy każde słowo binarne długości n jest podsłowem słowa ww. | |||
Następujący algorytm generuje takie słowo, co więcej jest ono leksykograficznie pierwsze spośród wszystkich możliwych | |||
Niech Cutfirst(x) oznacza obciecie x o pierwszy symbol, a Append(x,b) dopisanie litery b do słowa x na końcu. | |||
Algorytm Słowa-Cykliczne | |||
1 x := 1111..1 (n jedynek); | |||
2 Z := <math>\emptyset</math> ; wynik := słowo puste; | |||
3 while istnieje <math>b \in \{0,1\}</math> takie, że <math>Append(Cutfirst(x),b)\notin Z</math> do | |||
4 wybierz minimalne takie b ; | |||
5 Append(Cutfirst(x),b); | |||
6 insert(x,Z) ; | |||
7 Append(wynik,b); | |||
Na przykład dla n=3 wynik = 00010111, a dla n=2 wynik = 0011 | |||
Udowodnij poprawność algorytmu. | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"> | ||
Rozwiązanie | Rozwiązanie | ||
<div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible-content" style="display:none"> | ||
Zadanie ma to związek z pewną metodą konstrukcji cyklu Eulera, chociaż zadanie pozornie wydaje się nie mieć nic wspólnego z grafami. | |||
Mamy tu do czynienia z grafem ktorego węzłami są wszystkie słowa binarne długości n-1. | |||
Istnieje krawędż u \rightarrow v o etykieci a, gdy Append(Cutfirst(u),a)=v. | |||
Ciąg operacji w algorytmie Słowa-Cykliczne odpowiada zachłannej ścieżce Eulera która startuje z węzła <math>1^{n-1}</math>. patrz zadania w module Algorytmy grafowe. | |||
</div> | |||
</div> | </div> |
Aktualna wersja na dzień 10:29, 5 wrz 2023
Zadanie 1
Uzasadnij poprawność algorytmu obliczającego długość najkrótszego słowa pokrywającego dany tekst.
Rozwiązanie
Zadanie 2
Udowodnij, że w wersji on-line algorytmu KMP mamy
Rozwiązanie
Zadanie 3
Udowodnij, że w wersji on-line algorytmu KMP mamy
Rozwiązanie
Zadanie 4
Mamy zbiór słów, każde długości dwa, obliczyć długość minimalnego tekstu który zawiera wszystkie słowa.
Rozwiązanie
Zadanie 5
Udowodnij następującą ciekawą własność kombinatoryczną okresowości w tekstach. Niech oznacza najmniejszy wspólny dzielnik p,q.
Lemat [Lemat o okresowości]
Jeśli x ma okresy p, q oraz , to jest również okresem x.
Rozwiązanie
Zadanie 6
Lemat o okresowości można wzmocnić, osłabiając założenia. Udowodnij następujący lemat.
Lemat [Silny lemat o okresowości]
Jeśli x ma okresy p, q oraz , to jest również okresem x.
Rozwiązanie
Zadanie 7
Udowdnij poprawność algorytmu KMP realtime
Rozwiązanie
Zadanie 8
Przprowadź dokładny dowód tego, że algorytm Oszczędny KMP wykonuje co najwyżej 3/2 n porównań (schemat dowodu był już opisany w odpowiednim module)
Rozwiązanie
Zadanie 9
Słowa cykliczne (de Bruijna): Słowo binarne w długości dokładnie nazwiemy cyklicznym (słowem de Bruijna, który to wymyślił) rzędu n gdy każde słowo binarne długości n jest podsłowem słowa ww.
Następujący algorytm generuje takie słowo, co więcej jest ono leksykograficznie pierwsze spośród wszystkich możliwych
Niech Cutfirst(x) oznacza obciecie x o pierwszy symbol, a Append(x,b) dopisanie litery b do słowa x na końcu.
Algorytm Słowa-Cykliczne
1 x := 1111..1 (n jedynek);
2 Z := ; wynik := słowo puste;
3 while istnieje takie, że do
4 wybierz minimalne takie b ;
5 Append(Cutfirst(x),b);
6 insert(x,Z) ;
7 Append(wynik,b);
Na przykład dla n=3 wynik = 00010111, a dla n=2 wynik = 0011
Udowodnij poprawność algorytmu.
Rozwiązanie