Wstęp do programowania / Ćwiczenia 5: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Praktycznie wszystko
m Zastępowanie tekstu – „<math> ” na „<math>”
 
(Nie pokazano 72 wersji utworzonych przez 8 użytkowników)
Linia 1: Linia 1:
To są ćwiczenia z gramatyk bezkontekstowych.
{{powrot|WDP_Składnia_i_semantyka_instrukcji|do modułu Składnia i semantyka instrukcji}}
 
To są zadania na wyszukiwanie binarne.


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
Ogladaj rozwiązania __SHOWALL__<br>
Oglądaj wskazówki i rozwiązania __SHOWALL__<br>
Ukryj rozwiązania __HIDEALL__
Ukryj wskazówki i rozwiązania __HIDEALL__
</div>
</div>


==Zadanie 1 (palindromy)==
 
Napisz gramatykę generującą wszystkie poprawne palindromy nad alfabetem {0,1}.
== Zadanie 1 (Pierwsze wystąpienie x)==
Dana jest posortowana niemalejąco tablica A typu array[1..N] of integer i x typu integer. Znajdź
miejsce pierwszego wystąpienia x (lub 0 gdy nie ma żadnego x)


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
S → &epsilon; | 0 | 1 | 0S0 | 1S1
To zadanie było omawiane na wykładzie. Dla pełności włączamy je tu do zestawu.
'''function''' ZnajdźPierwsze(N,x:integer; A:array[1..N] of integer):integer;
//Tablica A posortowana niemalejąco; szukamy pierwszego wystąpienia x w A
'''var''' l,p,s : integer;
'''begin'''
  l:=1;
  p:=N;
  '''while''' l < p '''do''' '''begin'''
    s:=(l+p)div 2;
    '''if''' x > A[s] '''then''' l:=s+1
    '''else''' p:=s;
  '''end''';
  '''if''' A[l] = x '''then''' ZnajdźPierwsze:=l
  '''else''' ZnajdźPierwsze:=0;
'''end''';
''Koszt czasowy'': logarytmiczny względem N


''Zgodność'': (każde wygenerowane słowo jest palindromem) Dowód przez indukcję po długości wyprowadzenia.
''Koszt pamięciowy'': stały


Przypadek bazowy: wyprowadzenie długości 1. Są 3 przypadki: S → &epsilon;, S → 0, S → 1. Wszystkie wygenerowane słowa są palindromami.
[[pimp:modul5_1_1.html|Wizualizacja]]


Krok indukcyjny: załóżmy że wszystkie wyprowadzenia długości < n (dla danego n>1) są zgodne. Weźmy dowolne wyprowadzenie S →...→ x długości n. Wyprowadzenie to może zaczynać się od produkcji S → 0S0 lub S → 1S1. W pierwszym przypadku x=0y0, a z jego wyprowadzenia łatwo odczytać wyprowadzenie S →...→ y o długości n-1. Z założenia indukcyjnego y jest palindromem, zatem jest nim również słowo x=0y0. Analogicznie dowodzimy zgodność wyprowadzenia zaczynającego się od produkcji S → 1S1.
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Ćwiczenie 1</span>
<div class="mw-collapsible-content" style="display:none">
Jaka będzie wartość A[l] w przypadku, gdy x nie ma w tablicy A ?
</div>
</div>


''Pełność'': (każdy palindrom da się wygenerować) Dowód przez indukcję po długości słowa.
== Zadanie 2 (Ostatnie wystąpienie x)==
Dana jest posortowana niemalejąco tablica A typu array[1..N] of integer i x typu integer. Znajdź
miejsce ostatniego wystąpienia x (lub 0 gdy nie ma żadnego x)


Przypadek bazowy: jeśli słowo ma długość 0 lub 1, to jest to &epsilon;, 0 lub 1. Wszystkie te słowa dają się wygenerować.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
Krok indukcyjny: jeśli palindrom x ma długość > 1, to jest postaci 0y0 lub 1y1, gdzie y jest palindromem o mniejszej dlugości. Z założenia indukcyjnego S →...→ y. Zatem S → 0S0 →...→ 0y0 lub S → 1S1 →...→ 1y1 i otrzymaliśmy wyprowadzenie słowa x. 
<div class="mw-collapsible-content" style="display:none">
Funkcja div ciągnie w lewo. Jeśli liczba jest nieparzysta, wówczas obcina wynik w dół. Aby uzyskać symetryczny efekt, powinniśmy się zastanowić, jak zmusić div do zaokrąglania w górę.  
</div>
</div>
</div>
</div>
==Zadanie 2 (wyrażenia nawiasowe)==
Napisz gramatykę generującą wszystkie poprawne wyrażenia nawiasowe.


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
S → SS | (S) | &epsilon;
'''function''' ZnajdźOstatnie(N,x:integer; A:array[1..N] of integer):integer;
 
//Tablica A posortowana niemalejąco; szukamy ostatniego wystąpienia x w A
''Zgodność'': (każde wygenerowane słowo jest poprawnym wyrażeniem nawiasowym) Niech L oznacza język poprawnych wyrażeń nawiasowych. Dowód zgodności przez indukcję po długości wyprowadzenia.
'''var''' l,p,s : integer;
 
'''begin'''
Przypadek bazowy: poprzez wyprowadzenie długości 1 jest możliwe wygenerowanie tylko słowa &epsilon; i należy ono do L.
  l:=1;
 
  p:=N;
Krok indukcyjny: każde dłuższe wyprowadzenie zaczyna się od produkcji S → (S) lub S → SS. W pierwszym przypadku wygenerowane słowo będzie postaci (w), gdzie S →...→ w jest wyprowadzeniem o długości n-1, czyli w&isin;L z założenia indukcyjnego.
  '''while''' l < p '''do''' '''begin'''
    s:=(l+p+1)div 2;
    '''if''' x < A[s] '''then''' p:=s-1
    '''else''' l:=s;
  '''end''';
  '''if''' A[l] = x '''then''' ZnajdźOstatnie:=l
  '''else''' ZnajdźOstatnie:=0;
'''end''';
''Koszt czasowy'': logarytmiczny względem N


Podobnie w drugim przypadku, wygenerowane słowo będzie postaci uv, gdzie S →...→ u oraz S →...→ v są wyprowadzeniami o długości mniejszej niż n (suma długości tych wyprowadzeń wynosi n-1). Zatem u,v&isin;L, stąd uv&isin;L.
''Koszt pamięciowy'': stały


''Pełność'': (każde wyrażenie nawiasowe da się wyprowadzić) Dowód przez indukcję po długości wyrażenia. Wyrażenie o długości 0 (słowo puste &epsilon;) da się wyprowadzić.
[[pimp:modul5_2_1.html|Wizualizacja]]


Niech w będzie dowolnym wyrażeniem nawiasowym o długości n>0. Określmy funkcję <math>f_w(i)=\#_((w_1...w_i)-\#_)(w_1...w_i)</math>, czyli różnicę w liczbie wystąpień nawiasu otwierającego i zamykającego w prefiksie o długości i. Łatwo zauważyć, że:
* <math>f_w(0)=0</math>
* <math>f_w(n)=0</math>
* <math>f_w(i)\ge0</math> dla <math>i=0\dots n</math>
W przypadku gdy istnieje j takie, że <math>0<j<n</math> i <math>f_w(j)=0</math> słowa <math>w_1...w_j</math> oraz <math>w_{j+1}...w_n</math> są poprawnymi wyrażeniami nawiasowymi o długości mniejszej niż n. Zatem istnieją wyprowadzenia <math>S \rightarrow \cdots \rightarrow w_1...w_j</math> oraz <math>S \rightarrow \cdots \rightarrow w_{j+1}...w_n</math> i da się z nich złożyć wyprowadzenie <math>S \rightarrow SS \rightarrow \cdots \rightarrow w</math>.
W przypadku, gdy dla wszystkich j, <math>f_w(j)>0</math> słowo <math>w_2...w_{n-1}</math> jest poprawnym wyrażeniem nawiasowym o długości n-2, zatem wyprowadzalnym z S. Stąd łatwo otrzymać wyprowadzenie słowa w <math>S \rightarrow (S) \rightarrow \cdots \rightarrow w</math>.
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 2''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Ćwiczenie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
S → (S)S | &epsilon;
Jaka będzie wartość A[l] w przypadku, gdy x nie ma w tablicy A ?
 
''Zgodność'': oczywista.
 
''Pełność'': podobnie jak w Rozwiązaniu 1. Dla uzyskania danego słowa w o długości > 0 należy posłużyć się funkcją <math>f_w</math>. Przyglądając się '''pierwszej''' pozycji j>0 dla której <math>f_w(j)=0</math>, zauważamy, że słowa <math>w_2...w_{j-1}</math> oraz <math>w_{j+1}...w_n</math> są poprawnymi wyrażeniami nawiasowymi o mniejszej długości. Zatem można uzyskać wyprowadzenie słowa w <math>S \rightarrow (S)S \rightarrow \cdots \rightarrow w</math>.
</div>
</div>
</div>
</div>


==Zadanie 3==
== Zadanie 3 (Liczba wystąpień x)==
Podaj gramatykę języka słow w nad alfabetem {0,1} takich, że <math>\#_0(w)=\#_1(w)</math>
Dana jest posortowana niemalejąco tablica A typu array[1..N] of integer i x typu integer. Wyznacz liczbę wystąpień x w tablicy A.


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
S → SS | 0S1 | 1S0 | &epsilon;
Trzeba użyć wyszukiwania binarnego, a nie liniowego.
 
''Zgodność'': oczywista.
 
''Pełność'': podobnie jak w Zadaniu 2. Dla uzyskania słowa w o długości n należy przyjrzeć się wykresowi funkcji <math>f_w(i)=\#_0(w_1...w_i)-\#_1(w_1...w_i)</math>.
Jeśli funkcja ta nie ma miejsc zerowych poza 0 i n, pierwszą produkcją jest S → 0S1 lub S → 1S0. W przeciwnym przypadku w rozkłada się na dwa krótsze słowa o równej liczbie zer i jedynek i pierwszą produkcją jest S → SS.
</div>
</div>
</div>
</div>


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 2''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
S → 0S1S | 1S0S | &epsilon;
'''function''' LiczbaWystąpień(N,x:integer; A:array[1..N] of integer):integer;
//Tablica A posortowana niemalejąco; wyznaczamy liczbę wystąpień x w A
'''var''' p,l: integer;
'''begin'''
  l:= ZnajdźPierwsze(N,x,A);
  p:= ZnajdźOstatnie(N,x,A);
  '''if''' l<>0 '''then''' LiczbaWystąpień:=p-l+1
  '''else''' LiczbaWystąpień:=0
'''end''';
''Koszt czasowy'': logarytmiczny względem N
 
''Koszt pamięciowy'': stały
 
Wariant rozwiązania, w którym większość kodu ZnajdźPierwsze i ZnajdźOstatnie jest wpisana wprost do treści procedury:
'''function''' LiczbaWystąpień1(N,x:integer; A:array[1..N] of integer):integer;
//Tablica A posortowana niemalejąco; wyznaczamy liczbę wystąpień x w A
'''var''' p,l,p1,l1: integer;
'''begin'''
  l1:=1; p1:=n;
  '''while''' l1<>p1 '''do'''
    '''begin'''
        s:=(l1+p1) '''div''' 2;
        '''if''' A[s]<x '''then''' l:=s+1
        '''else''' p:=s
    '''end''';
  l:=l1;
  l1:=1; p1:=n;
  '''while''' l1<>p1 '''do'''
    '''begin'''
        s:=(l1+p1+1) '''div''' 2;
        '''if''' A[s]>x '''then''' p:=s-1
        '''else''' l:=s
    '''end''';
    p:=l1;
    LiczbaWystąpień1:=p-l+1
'''end''';
 


''Zgodność'': oczywista


''Pełność'': podobnie jak w Rozwiązaniu 1 i w Rozwiązaniu 2 Zadania 2.
Uwaga: czy  kod ten jest poprawny, gdy x'a nie ma w tablicy?
</div>
</div>
</div>
</div>


==Zadanie 4==
== Zadanie 4 (Wartość równa indeksowi)==
Podaj gramatykę języka słow w nad alfabetem {0,1} takich, że <math>\#_0(w)=\#_1(w)+1</math>
Dana jest posortowana rosnąco tablica A typu array[1..N] of integer.  Sprawdź czy występuje w niej element o wartości równej swojemu indeksowi. Jeśli tak, to wyznacz ten indeks, jeśli nie, to funkcja ma dać wartość 0.


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
<div class="mw-collapsible-content" style="display:none">
Jeśli A[i] < i, to też A[i-1] < i-1. I podobnie dla i-2, i-3, ... ,1. 
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
R → 0R1 | 1R0 | RR | &epsilon;
'''function''' Równy(N:integer; A:array[1..N] of integer):integer;
//Tablica A posortowana rosnąco; szukamy i, takiego że A[i]=i
'''var''' p,l,s: integer;
'''begin'''
  l:=1;
  p:=N;
  '''while''' l < p '''do''' '''begin'''
    s:=(l+p)div 2;
    '''if''' A[s] < s '''then''' l:=s+1
    '''else''' p:=s;
  '''end''';
  '''if''' (A[l]=l) '''then''' Równy:=l
  '''else''' Równy:=0;
'''end''';
Dla tablic posortowanych niemalejąco to rozwiązanie nie działa.


N → 0N1 | 1N0 | RN | NR | 0
''Koszt czasowy'': logarytmiczny względem N


symbol startowy: N
''Koszt pamięciowy'': stały


''Zgodność'': wiedząc (z Zadania 3), że R generuje słowa o równej liczbie 0 i 1, łatwo pokazać przez indukcję, że N generuje słowa, w których liczba 0 jest o jeden większa niż liczba 1.
[[pimp:modul5_4_1.html|Wizualizacja]]


''Pełność'': mając dane słowo w o długości > 1 zaczynamy od wskazania (dowolnego) nadmiarowego 0. Następnie postępujemy jak w zadaniu 3, nie licząc wskazanego 0, pamiętając przy tym, żeby ta część słowa, która zawiera wskazane 0, była wyprowadzana z N, a nie z R.
</div>
</div>
</div>
</div>
<!--
R → 0R1R | 1R0R | &epsilon;


N → 0N1R | 0R1N | 1N0R | 1R0N | 0
== Zadanie 5 (Maksimum w ciągu bitonicznym)==
Dana jest tablica A typu array[1..N] of integer, w której wartości ułożone są w ciąg bitoniczny (czyli istnieje 1 &le; i &le; N, takie że dla wszystkich k, takich że 1 &le; k < i zachodzi A[k] < A[k+1] a dla wszystkich k, takich że  i &le; k < N  zachodzi A[k] > A[k+1]). Znajdź maksimum w tym ciągu.


symbol startowy: N
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
-->
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
 
<div class="mw-collapsible-content" style="display:none">Szukamy pierwszego elementu, dla którego A[i] > A[i+1]. Trzeba uważać na przypadek gdy maksimum jest w A[N].
==Zadanie 5==
</div>
Podaj gramatykę generującą liczby w zapisie binarnym, które są podzielne przez 3.
</div>


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
S<sub>0</sub> → 0 | S<sub>0</sub>0 | S<sub>1</sub>1  
'''function''' MaksBitoniczny(N:integer; A:array[1..N] of integer):integer;
 
//Tablica A zawiera ciąg bitoniczny; szukamy indeksu maksymalnej wartości w tym ciągu
S<sub>1</sub> → 1 | S<sub>0</sub>1 | S<sub>2</sub>0
'''var''' p,l,s: integer;
'''begin'''
  '''if''' N=1 '''then''' MaksBitoniczny:=1  
  '''else'''
    '''if''' A[N-1] < A[N] '''then''' MaksBitoniczny:=N
    '''else''' '''begin'''
      l:=1;
      p:=N-1;
      '''while''' l < p '''do''' '''begin'''
        s:=(l+p)div 2;
        '''if''' A[s] < A[s+1] '''then''' l:=s+1
        '''else''' p:=s;
      '''end''';
      MaksBitoniczny:=l;
    '''end'''; 
'''end''';
''Koszt czasowy'': logarytmiczny względem N


S<sub>2</sub> → S<sub>1</sub>0 | S<sub>2</sub>1
''Koszt pamięciowy'': stały


symbol startowy: S<sub>0</sub>
[[pimp:modul5_5_1.html|Wizualizacja]]


''Zgodność'': Łatwo pokazać, że kolejne symbole generują liczby, które w dzieleniu przez 3 mają resztę odpowiednio 0, 1 i 2. Dwa przypadki bazowe są oczywiste, następnie weźmy na przykład produkcję S<sub>1</sub> → S<sub>2</sub>0. Jeśli (z założenia indukcyjnego)  S<sub>2</sub> wygeneruje liczbę w o reszcie 2, to wygenerowana przez S<sub>1</sub> liczba w0 będzie miała resztę 2×2 mod 3 = 1. Podobnie można sprawdzić wszystkie pozostałe produkcje.
''Pełność'': Przez indukcję po długości liczby pokażemy, że każdą liczbę o reszcie z dzielenia przez 3 wynoszącej i da się wygenerować z symbolu S<sub>i</sub>. Istotnie, dla liczb jednocyfrowych jest to oczywiste. Dla pozostałych, postaci wb, wystarczy popatrzeć na ostatnią cyfrę b. Reszta z dzielenia wb przez 3 oraz wartość b determinują resztę z dzielenia w przez 3. Dla wszystkich sześciu przypadków w naszej gramatyce istnieje odpowiednia produkcja. Następnie wystarczy użyć założenia indukcyjnego, aby wygenerować w.
</div>
</div>
</div>
</div>
== Zadanie 6 (Pierwiastek z x)==
Napisz program obliczający sufit z pierwiastka z x, dla <math>x \in N ,x>0</math> (oczywiście bez operacji pierwiastek).


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Pytanko 1''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
Jak należy zmodyfikować tę gramatykę, aby generowane liczby binarne nie mogły zaczynać się od 0 ?
Najprostsze rozwiązanie jest liniowe ze względu na wartość pierwiastka z x.
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Odpowiedź''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
S<sub>0</sub> → S<sub>0</sub>0 | S<sub>1</sub>1  
'''function''' SufitZPierwiastka1(x:integer):integer;
//Dla x > 0 wyznaczamy sufit z pierwiastka z x
'''var''' i: integer;
'''begin'''
  i:=1;
  '''while''' x > i*i '''do''' i := i+1;
  SufitZPierwiastka1 := i;
'''end''';
''Koszt czasowy'': pierwiastkowy względem x


S<sub>1</sub> → 1 | S<sub>0</sub>1 | S<sub>2</sub>0
''Koszt pamięciowy'': stały


S<sub>2</sub> → S<sub>1</sub>0 | S<sub>2</sub>1
[[pimp:modul5_6_1.html|Wizualizacja]]


S → S<sub>0</sub> | 0
symbol startowy: S
</div>
</div>
</div>
</div>


==Zadanie 6==
Podaj gramatykę generującą słowa nad alfabetem {0,1}, w których nie występuje podsłowo 000.


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1'''  
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span>
<div class="mw-collapsible-content" style="display:none">Oczywiście lepiej jest to zrobić binarnie. Szukamy takiej liczby całkowitej i z przedziału [1..x], że (i-1)*(i-1) < x &le; i*i.
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 2</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
S<sub>0</sub> → &epsilon; | S<sub>0</sub>1 | S<sub>1</sub>1 | S<sub>2</sub>1  
'''function''' SufitZPierwiastka2(x:integer):integer;
//Dla x > 0 wyznaczamy sufit z pierwiastka z x
'''var''' l,p,s : integer;
'''begin'''
  l:=1;
  p:=x;
  '''while''' l < p '''do''' '''begin'''
    s:=(l+p)div 2;
    '''if''' x > s*s '''then''' l:=s+1
    '''else''' p:=s;
  '''end''';
  SufitZPierwiastka2:=l;
'''end''';
''Koszt czasowy'': logarytmiczny względem x


S<sub>1</sub> → S<sub>0</sub>0
''Koszt pamięciowy'': stały


S<sub>2</sub> → S<sub>1</sub>0
[[pimp:modul5_6_2.html|Wizualizacja]]


S → S<sub>0</sub> | S<sub>1</sub> | S<sub>2</sub>
</div>
</div>


symbol startowy: S
===Inna wersja zadania===
A jak znaleźć podłogę z pierwiastka z x ?


Zgodność i pełność tej gramatyki wynika z faktu, że S<sub>j</sub> generuje wszystkie słowa w nie zawierające 000 i kończące się na j zer.  
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 3</span>
<div class="mw-collapsible-content" style="display:none">
Analogicznie jak w Rozwiązaniu 2.  
</div>
</div>
</div>
</div>


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 2''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 3</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
S<sub>0</sub> → &epsilon; | S<sub>0</sub>1 | S<sub>0</sub>01 | S<sub>0</sub>001  
'''function''' PodłogaZPierwiastka(x:integer):integer;
//Dla x > 0 wyznaczamy podłogę z pierwiastka z x
'''var''' l,p,s : integer;
'''begin'''
  l:=1;
  p:=x;
  '''while''' l < p '''do''' '''begin'''
    s:=(l+p+1)div 2;
    '''if''' x < s*s '''then''' p:=s-1
    '''else''' l:=s;
  '''end''';
  PodłogaZPierwiastka:=l;
'''end''';
Uwaga: porównaj różnice między Rozwiązaniami 2 i 3 oraz funkcjami ZnajdźPierwsze, ZnajdźOstatnie z Zadania 1 i 2.
''Koszt czasowy'': logarytmiczny względem x


S → S<sub>0</sub> | S<sub>0</sub>0 | S<sub>0</sub>00
''Koszt pamięciowy'': stały


symbol startowy: S
[[pimp:modul5_6_3.html|Wizualizacja]]


Ta gramatyka powstała z poprzedniej przez usunięcie symboli S<sub>1</sub> i S<sub>2</sub> i włączenie ich (pojedynczych) produkcji do produkcji pozostałych symboli.
</div>
</div>
</div>
</div>
== Zadanie 7 (BinPower)==
Dla zadanych x,n > 0 wyznacz x<sup>n</sup> (oczywiscie bez exp i ln).


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 3''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
Z → &epsilon; | 0 | 00
Oczywiście nie chodzi o to, by pomnożyć x przez siebie n-1 razy.
</div>
</div>


S → Z | S1Z
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span>
<div class="mw-collapsible-content" style="display:none">
Użyj podobnego pomysłu jak przy mnożeniu chłopów rosyjskich. Pamiętaj, że mnożenie ma się tak do dodawania, jak potęgowanie do mnożenia.
</div>
</div>
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
'''function''' BinPower(x,n:integer):integer;
// Dla x,n > 0 wyznaczamy x do potęgi n
'''var''' z,y,i: integer;
'''begin'''
  z:=1;
  y:=x;
  i:=n;
  '''while''' i > 0 '''do''' '''begin'''
    '''if''' (i mod 2 = 1) '''then''' z:=z*y;
    y:=y*y;
    i:=i div 2;
  '''end''';
  BinPower:=z;
'''end''';
''Koszt czasowy'': logarytmiczny względem N


symbol startowy: S
''Koszt pamięciowy'': stały


Z - krotki ciąg zer (mniej niż 3)
[[pimp:modul5_7_1.html|Wizualizacja]]


S - ciąg krótkich ciągów zer poprzedzielanych jedynkami
</div>
</div>
</div>
</div>
O ile istnieją proste algorytmy mnożące w czasie wielomianowym (choćby szkolne słupki), to w przypadku potęgowania nie ma oczywistego szybkiego algorytmu potęgującego. Można spytać, po co usprawniać kod potęgowania, gdy wykładniki w naturze wcale nie sa takie duże. Nic bardziej mylnego! W jednym z najpopularniejszych algorytmów kryptograficznych - kodowaniu RSA - używa się potęgowania o wykładnikach będących bardzo dużymi liczbami (zazwyczaj stukilkudziesięciocyfrowymi!). Poleglibyśmy sromotnie, gdybyśmy próbowali mnożyć odpowiednią liczbę razy przez siebie podstawę potęgowania.
== Zadanie 8 (Najdłuższy podciąg niemalejący) ==
Dana jest tablica A typu array[1..N] of integer, N > 1. Należy obliczyć długość najdłuższego podciągu niemalejącego w A.


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Dla ciekawskich ''' 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
Język opisany w tym zadaniu (i w Zadaniu 5) jest w istocie [[językiem regularnym]], czyli dającym się wygenerować bez rekurencji, a tylko poprzez iterację (czyli prostszym, niż ''zwykły'' język bezkontekstowy). Można to poznać po tym, że udało nam się stworzyć gramatykę, w której wszystkie produkcje są postaci X → Yz lub X → Y gdzie X i Y to symbole nieterminalne, a z to symbol terminalny.  
Kluczowe jest użycie dodatkowej tablicy B rozmiaru N, w której pod indeksem i przechowuje się minimalną wartość kończącą podciąg niemalejący o długości i w dotychczas przejrzanej części tablicy A,  od 1 do k. Żeby uwzględnić A[k+1], należy w tablicy B odnależć miejsce na A[k+1] (najlepiej binarnie).
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">Zacznijmy od pomocniczej funkcji ZnajdźPierwszyWiększy(A:array[1..N] of integer; l,p,x:integer):integer, która w tablicy A, na odcinku od l do p, wyznacza indeks pierwszego elementu o wartości większej od x przy założeniu że A[p] > x.
'''function''' ZnajdźPierwszyWiększy(C:array[1..N] of integer; l,p,x:integer):integer;
//Tablica C jest posortowana niemalejąco na odcinku od l do p, zakładamy, że C[p] > x;
//szukamy indeksu pierwszego elementu z lewej większego od x 
'''var''' s: integer;
'''begin'''
  '''while''' l < p '''do''' '''begin'''
    s:=(l+p+1)div 2;
    '''if''' x < C[s] '''then''' p:=s-1
    '''else''' l:=s;
  '''end''';
  '''if''' C[l] <= x '''then''' ZnajdźPierwszyWiększy:=l+1
  '''else''' ZnajdźPierwszyWiększy:=l;
'''end''';
 
Teraz funkcja MaxNiemalejący:
 
'''function''' MaxNiemalejący(N:integer; A:array[1..N] of integer):integer;
'''var''' ia,ib,z: integer;
    B: array[1..N] of integer;
'''begin'''
  ib:=1;
  B[ib]:=A[1];
  '''for''' ia:=2 '''to''' N '''do'''
    '''if''' A[ia] >= B[ib] '''then''' '''begin'''
      ib:=ib+1;   
      B[ib]:=A[ia];
    '''end'''
    '''else''' '''begin'''
      z:=ZnajdźPierwszyWiększy(B,1,ib,A[ia]);
      B[z]:=A[ia];
    '''end''';
  MaxNiemalejący:=ib;
'''end''';
Ponieważ dla każdego elementu A wykonujemy wyszukiwanie binarne w B to:
 
''Koszt czasowy'': O(N×logN)
 
''Koszt pamięciowy'': liniowy względem N
 
[[pimp:modul5_8_1.html|Wizualizacja]]


Języki regularne mają wiele wspólnego z [[wyrażeniami regularnymi]] używanymi w prostych operacjach na tekstach, takich jak wyszukiwanie i zastępowanie (np przez programy Unixowe [[grep]], [[sed]] itp.)
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Ćwiczenie 1</span>
<div class="mw-collapsible-content" style="display:none">Czy algorytm zachłanny by zadziałał? Zachłanność polegałaby na tym, że przedłużalibyśmy podciąg pod warunkiem, że rozważany element jest niemniejszy od ostatniego elementu dotychczas znalezionego maksymalnego podciągu.
</div>
</div>
</div>
</div>

Aktualna wersja na dzień 22:14, 11 wrz 2023

<<< Powrót do modułu Składnia i semantyka instrukcji

To są zadania na wyszukiwanie binarne.

Oglądaj wskazówki i rozwiązania __SHOWALL__
Ukryj wskazówki i rozwiązania __HIDEALL__


Zadanie 1 (Pierwsze wystąpienie x)

Dana jest posortowana niemalejąco tablica A typu array[1..N] of integer i x typu integer. Znajdź miejsce pierwszego wystąpienia x (lub 0 gdy nie ma żadnego x)

Rozwiązanie 1

Ćwiczenie 1

Zadanie 2 (Ostatnie wystąpienie x)

Dana jest posortowana niemalejąco tablica A typu array[1..N] of integer i x typu integer. Znajdź miejsce ostatniego wystąpienia x (lub 0 gdy nie ma żadnego x)

Wskazówka 1

Rozwiązanie 1

Ćwiczenie 1

Zadanie 3 (Liczba wystąpień x)

Dana jest posortowana niemalejąco tablica A typu array[1..N] of integer i x typu integer. Wyznacz liczbę wystąpień x w tablicy A.

Wskazówka 1

Rozwiązanie 1

Zadanie 4 (Wartość równa indeksowi)

Dana jest posortowana rosnąco tablica A typu array[1..N] of integer. Sprawdź czy występuje w niej element o wartości równej swojemu indeksowi. Jeśli tak, to wyznacz ten indeks, jeśli nie, to funkcja ma dać wartość 0.

Wskazówka 1

Rozwiązanie 1

Zadanie 5 (Maksimum w ciągu bitonicznym)

Dana jest tablica A typu array[1..N] of integer, w której wartości ułożone są w ciąg bitoniczny (czyli istnieje 1 ≤ i ≤ N, takie że dla wszystkich k, takich że 1 ≤ k < i zachodzi A[k] < A[k+1] a dla wszystkich k, takich że i ≤ k < N zachodzi A[k] > A[k+1]). Znajdź maksimum w tym ciągu.

Wskazówka 1

Rozwiązanie 1

Zadanie 6 (Pierwiastek z x)

Napisz program obliczający sufit z pierwiastka z x, dla xN,x>0 (oczywiście bez operacji pierwiastek).

Wskazówka 1

Rozwiązanie 1


Wskazówka 2

Rozwiązanie 2

Inna wersja zadania

A jak znaleźć podłogę z pierwiastka z x ?

Wskazówka 3

Rozwiązanie 3

Zadanie 7 (BinPower)

Dla zadanych x,n > 0 wyznacz xn (oczywiscie bez exp i ln).

Wskazówka 1

Wskazówka 2

Rozwiązanie 1

O ile istnieją proste algorytmy mnożące w czasie wielomianowym (choćby szkolne słupki), to w przypadku potęgowania nie ma oczywistego szybkiego algorytmu potęgującego. Można spytać, po co usprawniać kod potęgowania, gdy wykładniki w naturze wcale nie sa takie duże. Nic bardziej mylnego! W jednym z najpopularniejszych algorytmów kryptograficznych - kodowaniu RSA - używa się potęgowania o wykładnikach będących bardzo dużymi liczbami (zazwyczaj stukilkudziesięciocyfrowymi!). Poleglibyśmy sromotnie, gdybyśmy próbowali mnożyć odpowiednią liczbę razy przez siebie podstawę potęgowania.

Zadanie 8 (Najdłuższy podciąg niemalejący)

Dana jest tablica A typu array[1..N] of integer, N > 1. Należy obliczyć długość najdłuższego podciągu niemalejącego w A.

Wskazówka 1

Rozwiązanie 1

Ćwiczenie 1