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

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Pi (dyskusja | edycje)
Nie podano opisu zmian
 
(Nie pokazano 117 wersji utworzonych przez 11 użytkowników)
Linia 1: Linia 1:
{{powrot|WDP_Wprowadzenie_do_programowania|do modułu Wprowadzenie do programowania}}
Ta strona zawiera podstawowe zadania na tablice.
Ta strona zawiera podstawowe zadania na tablice.


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
Ogladaj wskazówki i rozwiązania __SHOWALL__<br>
Oglądaj wskazówki i rozwiązania __SHOWALL__<br>
Ukryj wskazówki i rozwiązania __HIDEALL__
Ukryj wskazówki i rozwiązania __HIDEALL__
</div>
</div>
Linia 17: Linia 19:
#Robot potrafi zapamiętać tylko kilka wartości z przedziału 0..N+1.
#Robot potrafi zapamiętać tylko kilka wartości z przedziału 0..N+1.
#Nie można założyć, że występuje choć jeden żeton w każdym z kolorów.  
#Nie można założyć, że występuje choć jeden żeton w każdym z kolorów.  


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 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">
Należy przesuwać się indeksem c od początku tablicy zaś indeksem b od końca. Intencją jest utrzymywanie następującego niezmmiennika: wszystkie elementy tablicy o indeksach mniejszych od c są czerwone, zaś wiekszych od b są białe. Indeksy c i b będą się do siebie zbliżać i ostatecznie gdy c będzie równe b to tablica będzie uporządkowana.  
Należy przesuwać się indeksem c od początku tablicy, zaś indeksem b od końca. Intencją jest utrzymywanie następującego niezmmiennika: wszystkie elementy tablicy o indeksach mniejszych od c są czerwone, zaś wiekszych od b są białe. Indeksy c i b będą się do siebie zbliżać i ostatecznie gdy c będzie równe b, to tablica będzie uporządkowana.</div>
</div>
</div>
</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">
  '''program''' FlagaPolska1(N:integer; A:array[1..N] of integer);
  '''program''' FlagaPolska1(N:integer; A:array[1..N] of integer);
Linia 46: Linia 49:
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 2'''
<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">
<div class="mw-collapsible-content" style="display:none">
Rozwiązanie 1 optymalizuje liczbę sprawdzeń kolorów, ale może niepotrzebnie zamieniać białe z białymi. Można tego uniknąć wprowadzając dodatkową pętlę po białych od końca tablicy.
Rozwiązanie 1 optymalizuje liczbę sprawdzeń kolorów, ale może niepotrzebnie zamieniać białe z białymi. Można tego uniknąć wprowadzając dodatkową pętlę po białych od końca tablicy.</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 2</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' FlagaPolska2(N:integer; A:array[1..N] of integer);
  '''program''' FlagaPolska2(N:integer; A:array[1..N] of integer);
Linia 72: Linia 77:
     '''end''';
     '''end''';
  '''end'''.
  '''end'''.
W rozwiązaniu 2 są dwie zagnieżdżone pętle while. Trzeba zwrócić uwagę, że gdyby nie warunek c<b to w przypadku tablicy zawierającej same białe żetony doszłoby do wyjścia poza zakres (odwołanie do Kol(0)).  
W rozwiązaniu 2 są dwie zagnieżdżone pętle while. Trzeba zwrócić uwagę, że gdyby nie warunek c<b, to w przypadku tablicy zawierającej same białe żetony doszłoby do wyjścia poza zakres (odwołanie do Kol(0)).  


''Koszt czasowy'': liniowy względem N
''Koszt czasowy'': liniowy względem N
Linia 79: Linia 84:
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 3'''
<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">  
<div class="mw-collapsible-content" style="display:none">
W Rozwiązaniu 2 można uniknąć zagnieżdżonych while'i, trzeba jednak uważać aby nie sprawdzać kilka razy koloru tego samego żetonu.
W Rozwiązaniu 2 można uniknąć zagnieżdżonych while'i, trzeba jednak uważać, aby nie sprawdzać kilka razy koloru tego samego żetonu. </div>
</div>
</div>
</div>
<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">Rozwiązanie 3</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' FlagaPolska3(N:integer; A:array[1..N] of integer);
  '''program''' FlagaPolska3(N:integer; A:array[1..N] of integer);
Linia 95: Linia 102:
  '''begin'''
  '''begin'''
   c:=1; kc:=Kol(c);
   c:=1; kc:=Kol(c);
   b:=n; kc:=Kol(b);
   b:=n; kb:=Kol(b);
   '''while''' c < b '''do'''  
   '''while''' c < b '''do'''  
     '''if''' kc=czerwony '''then''' '''begin'''  
     '''if''' kc=czerwony '''then''' '''begin'''  
Linia 116: Linia 123:
       '''end;'''
       '''end;'''
  '''end'''.
  '''end'''.
W rozwiązaniu 3 każdy żeton jest sprawdzany co najwyżej raz, a każda zamiana ustawia na dobrych miejscach 2 żetony (inaczej mówiąc tych żetonów nie trzeba już będzie przestawiać). A więc wszystkich zamian jest co najwyżej N div 2. Alternatywne rozwiązanie, unikające zagnieżdżonych pętli jest poniżej.  
W rozwiązaniu 3 każdy żeton jest sprawdzany co najwyżej raz, a każda zamiana ustawia na dobrych miejscach 2 żetony (inaczej mówiąc, tych żetonów nie trzeba już będzie przestawiać). A więc wszystkich zamian jest co najwyżej N div 2. Alternatywne rozwiązanie, unikające zagnieżdżonych pętli jest poniżej.  


''Koszt czasowy'': liniowy względem N
''Koszt czasowy'': liniowy względem N
Linia 123: Linia 130:
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 4'''
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 4</span>
<div class="mw-collapsible-content" style="display:none">  
<div class="mw-collapsible-content" style="display:none">
Alternatywne rozwiązanie, unikające zagnieżdżonych pętli jest poniżej. Tu oba indeksy b i c przesuwają się od początku tablicy a niezmiennikiem jest to, że wszystkie elementy tablicy o indeksach  mniejszych od c są czerwone, zaś te o indeksach wiekszych równych od c i miejszych od b są białe.
Alternatywne rozwiązanie, unikające zagnieżdżonych pętli jest poniżej. Tu oba indeksy b i c przesuwają się od początku tablicy a niezmiennikiem jest to, że wszystkie elementy tablicy o indeksach  mniejszych od c są czerwone, zaś te o indeksach większych lub równych c i miejszych od b są białe. </div>
</div>
</div>
</div>


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 4'''
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 4</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' FlagaPolska4(N:integer; A:array[1..N] of integer);
  '''program''' FlagaPolska4(N:integer; A:array[1..N] of integer);
Linia 153: Linia 161:
</div>
</div>
</div>
</div>
<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">Ćwiczenie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
Dla jakich danych algorytm przedstawiony w Rozwiązaniu 4 dokona N-1 zamian?
Dla jakich danych algorytm przedstawiony w Rozwiązaniu 4 dokona N-1 zamian?
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Pytanko 2'''
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Ćwiczenie 2</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
Jak trzeba by zmienić powyższe rozwiązania, gdyby zamiana Z(i,j) była dozwolona tylko dla i <> j ?
Jak trzeba by zmienić powyższe rozwiązania, gdyby zamiana Z(i,j) była dozwolona tylko dla i <> j ?
</div>
</div>
</div>
</div>


== Zadanie 2 (Flaga trójkolorowa) ==
== Zadanie 2 (Flaga trójkolorowa) ==
Linia 171: Linia 182:


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 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">
Rozwiązanie dla flagi trójkolorowej jest uogólnieniem rozwiązania dla flagi dwukolorowej. Rozwiązanie 1 poniżej jest kombinacją rozwiązań 3 i 4 z zadania 1; zaś Rozwiązanie 2 poniżej jest bezpośrednim uogólnieniem  rozwiązania 4 z zadania 1. Jeśli chodzi o liczbę zamian to lepsze wydaje się Rozwiązanie 1, gdyż od razu na dobre (ostateczne) miejsca trafiają elementy ujemne i dodatnie.
Rozwiązanie dla flagi trójkolorowej jest uogólnieniem rozwiązania dla flagi dwukolorowej. Rozwiązanie 1 poniżej jest kombinacją rozwiązań 3 i 4 z zadania 1; zaś Rozwiązanie 2 poniżej jest bezpośrednim uogólnieniem  rozwiązania 4 z zadania 1. Jeśli chodzi o liczbę zamian, to lepsze wydaje się Rozwiązanie 1, gdyż od razu na dobre (ostateczne) miejsca trafiają elementy ujemne i dodatnie.
</div>
</div>
</div>
</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">
  '''program''' FlagaTrójkolorowa(N:integer; A:array[1..N] of integer);
  '''program''' FlagaTrójkolorowa(N:integer; A:array[1..N] of integer);
Linia 199: Linia 211:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_2_1.html|Wizualizacja]]
</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 2</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' FlagaTrójkolorowa(N:integer; A:array[1..N] of integer);
  '''program''' FlagaTrójkolorowa(N:integer; A:array[1..N] of integer);
Linia 216: Linia 232:
         r:=r+1;
         r:=r+1;
       '''end'''
       '''end'''
       '''else''' '''begin''' //zamieniamy cyklicznie A[m], A[r] i A[w]
       '''else''' '''begin''' //zamieniamy cyklicznie A[m], A[r] i A[w] jeśli m<>r; wpp zamieniamy A[m] i A[w]
         pom:=A[m]; A[m]:=A[w]; A[w]:=A[r]; A[r]:=pom;  
         pom:=A[m];  
        A[m]:=A[w];  
        '''if''' (m<>r) '''then''' '''begin'''
          A[w]:=A[r];  
          A[r]:=pom;
        '''end'''
        '''else''' A[w]:=pom;  
         m:=m+1;
         m:=m+1;
         r:=r+1;
         r:=r+1;
Linia 226: Linia 248:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_2_2.html|Wizualizacja]]
</div>
</div>
</div>
</div>
Linia 231: Linia 256:
== Zadanie 3 (Najdłuższe plateau) ==
== Zadanie 3 (Najdłuższe plateau) ==
Napisz program znajdujący w zadanej tablicy A typu array[1..N] of integer, N > 0,  długość najdłuższego stałego segmentu (spójnego fragmentu tablicy).
Napisz program znajdujący w zadanej tablicy A typu array[1..N] of integer, N > 0,  długość najdłuższego stałego segmentu (spójnego fragmentu tablicy).
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 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">
Zadanie to można rozwiązać używając dwóch pętli; zewnętrznej (po możliwych początkach segmentu) i wewnętrznej (w której szukamy końca segmentu stałego).
Zadanie to można rozwiązać używając dwóch pętli; zewnętrznej (po możliwych początkach segmentu) i wewnętrznej (w której szukamy końca segmentu stałego).
</div>
</div>
</div>
</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ąznie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' NajdłuższePlateau1(N:integer; A:array[1..N] of integer);
  '''program''' NajdłuższePlateau1(N:integer; A:array[1..N] of integer);
  '''var''' l,p,w,maks: integer;
  '''var''' l,p,w,maks: integer;
  koniec:boolean;
  '''begin'''
  '''begin'''
   l:=1; w:=A[l]; maks:=1;  
   l:=1; w:=A[l]; maks:=1;  
Linia 257: Linia 285:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_3_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 2'''
<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">
<div class="mw-collapsible-content" style="display:none">
Dokładnie to samo rozwiązanie można zapisać używając jednej pętli.  
Dokładnie to samo rozwiązanie można zapisać używając jednej pętli.  
</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ąznie 2</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' NajdłuższePlateau2(N:integer; A:array[1..N] of integer);
  '''program''' NajdłuższePlateau2(N:integer; A:array[1..N] of integer);
  '''var''' w,p,dl,maks: integer;
  '''var''' w,p,dl,maks: integer;
  koniec:boolean;
  '''begin'''
  '''begin'''
   w:=A[1]; dl:=1; p:=2; maks:=1;  
   w:=A[1]; dl:=1; maks:=1;  
   '''for''' p:=2 '''to''' N '''do''' '''begin'''
   '''for''' p:=2 '''to''' N '''do''' '''begin'''
     '''if''' A[p]=w '''then''' dl:=dl+1
     '''if''' A[p]=w '''then''' dl:=dl+1
     '''else''' '''begin'''
     '''else''' '''begin'''
       maks:=max(maks, dl);
       maks:=max(maks, dl);
      w:=A[p];
       dl:=1;
       dl:=1;
     '''end''';
     '''end''';
Linia 284: Linia 320:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_3_2.html|Wizualizacja]]
</div>
</div>
</div>
</div>
<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">Ćwiczenie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
Czy przedostatnia linia programu w Rozwiązaniu 2 jest potrzebna? Co by było gdyby jej nie było ?
Czy przedostatnia linia programu w Rozwiązaniu 2 jest potrzebna? Co by było, gdyby jej nie było?
</div>
</div>
</div>
</div>
===Inna wersja zadania===  
===Inna wersja zadania===  
A co było gdyby tablica była posortowana ?
A co byłoby gdyby tablica była posortowana ?
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 3'''
<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">
<div class="mw-collapsible-content" style="display:none">
Podczas przechodzenia tablicy indeksem i od lewej do prawej, zmiana maks - dotychczas odnalezionej wartości najdłuższego plateau - zachodzi tylko wtedy gdy A[i] wydłuża ostatnie plateau do długości maks+1. Ponieważ tablica jest posortowana to wystarczy porównywać wartości A[i] i A[i-maks].   
Podczas przechodzenia tablicy indeksem i od lewej do prawej, zmiana maks - dotychczas odnalezionej wartości najdłuższego plateau - zachodzi tylko wtedy gdy A[i] wydłuża ostatnie plateau do długości maks+1. Ponieważ tablica jest posortowana, wystarczy porównywać wartości A[i] i A[i-maks].   
</div>
</div>
</div>
</div>
<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">Rozwiąznie 3</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' NajdłuższePlateau3(N:integer; A:array[1..N] of integer);
  '''program''' NajdłuższePlateau3(N:integer; A:array[1..N] of integer);
Linia 313: Linia 357:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_3_3.html|Wizualizacja]]
</div>
</div>
</div>
</div>
Linia 318: Linia 365:
== Zadanie 4 (Segment o maksymalnej sumie) ==
== Zadanie 4 (Segment o maksymalnej sumie) ==
Napisz program znajdujący w zadanej tablicy A typu array[1..N] of integer, N > 0, maksymalną sumę segmentu (spójnego fragmentu tablicy). Przyjmujemy, że segment pusty ma sumę 0.
Napisz program znajdujący w zadanej tablicy A typu array[1..N] of integer, N > 0, maksymalną sumę segmentu (spójnego fragmentu tablicy). Przyjmujemy, że segment pusty ma sumę 0.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 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">
Najprostsze rozwiązanie to dla wszystkich możliwych segmentów policzyć ich sumę.
Najprostsze rozwiązanie to dla wszystkich możliwych segmentów policzyć ich sumę.
</div>
</div>
</div>
</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">
  '''program''' SegmentOMaksymalnejSumie1(N:integer; A:array[1..N] of integer);
  '''program''' SegmentOMaksymalnejSumie1(N:integer; A:array[1..N] of integer);
Linia 342: Linia 391:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_4_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 2''' 
<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">
<div class="mw-collapsible-content" style="display:none">
W powyższym rozwiązaniu sumę pewnych segmantów liczy się wiele razy. Lepiej, dla danego początku l obliczać po kolei sumy coraz dłuższych segmentów zaczynających sie w l.
W powyższym rozwiązaniu sumę pewnych segmentów liczy się wiele razy. Lepiej dla danego początku l obliczać po kolei sumy coraz dłuższych segmentów zaczynających sie w l.
</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 2</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' SegmentOMaksymalnejSumie2(N:integer; A:array[1..N] of integer);
  '''program''' SegmentOMaksymalnejSumie2(N:integer; A:array[1..N] of integer);
Linia 368: Linia 422:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_4_2.html|Wizualizacja]]
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 3'''  <div class="mw-collapsible-content" style="display:none">
<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">
Niech Pref(i) oznacza sumę elemetów tablicy od 1 do i włącznie. Suma segmentu od l do p to oczywiście Pref(p) - Pref(l-1). Maksymalną sumę segmentu kończącego się w p uzyskamy odejmując od Pref(p) minimalne Pref(i) gdzie i przebiega [1..p].
Niech Pref(i) oznacza sumę elemetów tablicy od 1 do i włącznie. Suma segmentu od l do p to oczywiście Pref(p) - Pref(l-1). Maksymalną sumę segmentu kończącego się w p uzyskamy odejmując od Pref(p) minimalne Pref(i) gdzie i przebiega [1..p].
</div>
</div>
</div>
</div>
<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">Rozwiązanie 3</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program'''  SegmentOMaksymalnejSumie3(N:integer; A:array[1..N] of integer);
  '''program'''  SegmentOMaksymalnejSumie3(N:integer; A:array[1..N] of integer);
Linia 382: Linia 442:
  '''begin'''
  '''begin'''
   maks:=0;
   maks:=0;
   mini_pref:=0
   mini_pref:=0;
   biez_pref:=0;
   biez_pref:=0;
   '''for''' i:=1 '''to''' N '''do''' '''begin'''
   '''for''' i:=1 '''to''' N '''do''' '''begin'''
     biez_pref:=biez_pref+A[i]);
     biez_pref:=biez_pref+A[i];
     mini_pref:=min(mini_pref,biez_pref);
     mini_pref:=min(mini_pref,biez_pref);
     maks:=max(maks, biez_pref-mini_pref);
     maks:=max(maks, biez_pref-mini_pref);
Linia 393: Linia 453:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_4_3.html|Wizualizacja]]
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 4'''  <div class="mw-collapsible-content" style="display:none">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 4</span>
Poniższe rozwiązanie opiera się na spostrzeżeniu, że jeśli suma pewnego segmentu o początku w l i końcu w p jest ujemna, lub nawet równa zero, to nie ma sensu tego segmantu przedłużać. Co więcej wszystkie segmenty o początkach pomiędzy l i p będą podsegmentami tego dotychczas rozpatrywanego, więc nie ma sensu ich rozważać przy poszukiwaniu segmantu o maksymalnej sumie. Jedyną sensowną możliwością jest rozpatrywanie segmentów które zaczynają się od p+1.   
<div class="mw-collapsible-content" style="display:none">
Poniższe rozwiązanie opiera się na spostrzeżeniu, że jeśli suma pewnego segmentu o początku w l i końcu w p jest ujemna, lub nawet równa zero, to nie ma sensu tego segmentu przedłużać. Co więcej, wszystkie segmenty o początkach pomiędzy l i p będą podsegmentami tego dotychczas rozpatrywanego, więc nie ma sensu ich rozważać przy poszukiwaniu segmentu o maksymalnej sumie. Jedyną sensowną możliwością jest rozpatrywanie segmentów które zaczynają się od p+1.   
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 4'''
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 4</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program'''  SegmentOMaksymalnejSumie4(N:integer; A:array[1..N] of integer);
  '''program'''  SegmentOMaksymalnejSumie4(N:integer; A:array[1..N] of integer);
  '''var''' l,p,i,biez,maks: integer;
  '''var''' l,p,i,maks,suma: integer;
  '''begin'''
  '''begin'''
   l:=1;
   l:=1;
   p:=2;
   p:=1;
   suma:=A[l];   
   suma:=0;   
   maks:=max(0,suma);
   maks:=0;
   while p <= N '''do'''
   while p <= N '''do'''
     '''if''' suma+A[p] <= 0 '''then''' '''begin'''
     '''if''' suma+A[p] <= 0 '''then''' '''begin'''
       l:=p+1;
       l:=p+1;
       suma:=A[l];
       suma:=0;
       p:=l+1;
       p:=l;
      maks:=max(0,suma);
    '''end'''
     '''else''' '''begin'''
     '''else''' '''begin'''
       suma:=suma+A[p];
       suma:=suma+A[p];
       maks:max(0,suma);
       maks:=max(maks,suma);
       p:=p+1;
       p:=p+1;
     '''end''';
     '''end''';
  '''end'''.
  '''end'''.
W powyższym programie suma=A[l]+...+A[p-1] i jest to największa suma kończąca się na p-1 (przyjmując, że suma pustego ciągu też kończy się na p-1).
Ponieważ jest to rozwiązanie działające w czasie liniowym od N (p zwiększa się w każdym obrocie pętli) a wszystkich segmentów jest kwadratowo wiele, powstaje wątpliwość czy przypadkiem nie omijamy
Ponieważ jest to rozwiązanie działające w czasie liniowym od N (p zwiększa się w każdym obrocie pętli) a wszystkich segmentów jest kwadratowo wiele, powstaje wątpliwość czy przypadkiem nie omijamy
segmentu a maksymalnej sumie. To trzeba by udowodnić. Temat ten będzie poruszany w module o niezmiennikach i logice Hoare'a.
segmentu o maksymalnej sumie. To trzeba by udowodnić. Temat ten będzie poruszany w module o niezmiennikach i logice Hoare'a.  


''Koszt czasowy'': liniowy względem N
''Koszt czasowy'': liniowy względem N


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_4_4.html|Wizualizacja]]
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 5'''
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 5</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
Poniżej znajduje się inaczej (zwięźlej) zapisane Rozwiązanie 4. W tym rozwiązaniu nie odwołujemy się bezpośrednio do początku i końca aktualnego segmentu, a tylko do jego sumy (biez).  
Poniżej znajduje się inaczej (zwięźlej) zapisane Rozwiązanie 4. W tym rozwiązaniu nie odwołujemy się bezpośrednio do początku i końca aktualnego segmentu, a tylko do jego sumy (biez).  
Linia 447: Linia 520:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_4_5.html|Wizualizacja]]
</div>
</div>
</div>
</div>
Linia 452: Linia 528:
== Zadanie 5 (Część wspólna zbiorów) ==
== Zadanie 5 (Część wspólna zbiorów) ==
Dane są dwie tablice A i B typu array[1..N] of integer, N > 0. Obie są
Dane są dwie tablice A i B typu array[1..N] of integer, N > 0. Obie są
posortowane rosnąco. Należy traktując A i B jako reprezentacje dwu
posortowane rosnąco. Należy traktując A i B jako reprezentacje dwóch
zbiorów wypisać (operacją write) cześć wspólną tych zbiorów.
zbiorów wypisać (operacją write) część wspólną tych zbiorów.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1'''  <div class="mw-collapsible-content" style="display:none">
<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">
Będziemy przesuwać się po tablicach od prawej do lewej indeksami ia i ib. Za każdym obrotem pętli przesuwamy ten indeks pod którym jest miejsza wartość, lub oba gdy mają takie same wartości.   
Będziemy przesuwać się po tablicach od prawej do lewej indeksami ia i ib. Za każdym obrotem pętli przesuwamy ten indeks pod którym jest miejsza wartość, lub oba gdy mają takie same wartości.   
</div>
</div>
</div>
</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ąznie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' CzęśćWspólna(N:integer; A,B:array[1..N] of integer);
  '''program''' CzęśćWspólna(N:integer; A,B:array[1..N] of integer);
Linia 470: Linia 548:
     '''if''' A[ia] < B[ib] '''then''' ia:=ia+1
     '''if''' A[ia] < B[ib] '''then''' ia:=ia+1
     '''else'''  
     '''else'''  
       '''if''' A[ia] > B[ib] '''then''' ib:=ib+1;
       '''if''' A[ia] > B[ib] '''then''' ib:=ib+1
       '''else''' '''begin'''
       '''else''' '''begin'''
           write(A{ia], ' ');
           write(A[ia], ' ');
           ia:=ia+1;
           ia:=ia+1;
           ib:=ib+1;
           ib:=ib+1;
Linia 480: Linia 558:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_5_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>
Linia 487: Linia 568:
posortowane rosnąco. Należy traktując A i B jako reprezentacje dwu
posortowane rosnąco. Należy traktując A i B jako reprezentacje dwu
zbiorów wypisać (operacją write) sumę tych zbiorów.
zbiorów wypisać (operacją write) sumę tych zbiorów.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1'''  <div class="mw-collapsible-content" style="display:none">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
Dopóki istnieją elementy w obu tablicach przesuwamy się tak jak przy obliczaniu części wspólnej, potem obługujemy końcówki tablic.
<div class="mw-collapsible-content" style="display:none">
Dopóki istnieją elementy w obu tablicach, przesuwamy się tak, jak przy obliczaniu części wspólnej, potem obługujemy końcówki tablic.
</div>
</div>
</div>
</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">
  '''program''' Suma(N:integer; A,B:array[1..N] of integer);
  '''program''' Suma(N:integer; A,B:array[1..N] of integer);
Linia 502: Linia 586:
   '''while''' (ia <= N) '''and''' (ib <= N) '''do''' //dopóki są elementy w obu tablicach
   '''while''' (ia <= N) '''and''' (ib <= N) '''do''' //dopóki są elementy w obu tablicach
     '''if''' A[ia] < B[ib] '''then''' '''begin'''
     '''if''' A[ia] < B[ib] '''then''' '''begin'''
       write(A{ia], ' ');
       write(A[ia], ' ');
       ia:=ia+1;
       ia:=ia+1;
     '''end'''
     '''end'''
     '''else'''  
     '''else'''  
       '''if''' A[ia] > B[ib] '''then''' '''begin'''
       '''if''' A[ia] > B[ib] '''then''' '''begin'''
         write(B{ib], ' ');
         write(B[ib], ' ');
         ib:=ib+1;
         ib:=ib+1;
       '''end'''  
       '''end'''  
       '''else''' '''begin'''
       '''else''' '''begin'''
         write(A{ia], ' ');
         write(A[ia], ' ');
         ia:=ia+1;
         ia:=ia+1;
         ib:=ib+1;
         ib:=ib+1;
       '''end''';
       '''end''';
   '''while''' ia <= N '''do''' write(A{ia], ' '); //obsługa końcówki A
   '''for''' ia:=ia '''to''' N '''do''' write(A[ia], ' '); //obsługa końcówki A
   '''while''' ib <= N '''do''' write(B{ib], ' '); //obsługa końcówki B
   '''for''' ib:=ib '''to''' N '''do''' write(B[ib], ' '); //obsługa końcówki B
  '''end'''.
  '''end'''.
''Koszt czasowy'': liniowy względem N
''Koszt czasowy'': liniowy względem N


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_6_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>
<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">Ćwiczenie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
Z dwóch pętli while obsługujących końcówki tablic A i B w Rozwiązaniu 1 wykona się co najwyżej jedna. W jakich sytuacjach nie wykona się żadna z nich ?
Z dwóch pętli while obsługujących końcówki tablic A i B w Rozwiązaniu 1 wykona się co najwyżej jedna. W jakich sytuacjach nie wykona się żadna z nich ?
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 2'''  <div class="mw-collapsible-content" style="display:none">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span>
Można próbować modyfikować rozwiązanie zadania o części wspólnej, tak by oddać analogię między sumą i częścią wspólną zbiorów. Prowadziłoby to do warunku (ia <= N) or (ib <= N) w głównej pętli while.  Trzeba jednak na nowo zdefiniować co to znaczy że pod danym indeksem jest mniejsza wartość niż pod innym indeksem, w sytuacji gdy jeden z tych indeksów może być większy od N.
<div class="mw-collapsible-content" style="display:none">
Można próbować modyfikować rozwiązanie zadania o części wspólnej, tak by oddać analogię między sumą i częścią wspólną zbiorów. Prowadziłoby to do warunku (ia <= N) or (ib <= N) w głównej pętli while.  Trzeba jednak na nowo zdefiniować co to znaczy, że pod danym indeksem jest mniejsza wartość niż pod innym indeksem, w sytuacji gdy jeden z tych indeksów może być większy od N.
</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 2</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' Suma(N:integer; A,B:array[1..N] of integer);
  '''program''' Suma(N:integer; A,B:array[1..N] of integer);
Linia 552: Linia 644:
   '''while''' (ia <= N) '''or''' (ib <= N) '''do'''  
   '''while''' (ia <= N) '''or''' (ib <= N) '''do'''  
     '''if''' mniejsze(ia,ib) '''then''' '''begin'''
     '''if''' mniejsze(ia,ib) '''then''' '''begin'''
       write(A{ia], ' ');
       write(A[ia], ' ');
       ia:=ia+1;
       ia:=ia+1;
     '''end'''
     '''end'''
     '''else'''  
     '''else'''  
       '''if''' mniejsze(ib,ia) '''then''' '''begin'''
       '''if''' mniejsze(ib,ia) '''then''' '''begin'''
         write(B{ib], ' ');
         write(B[ib], ' ');
         ib:=ib+1;
         ib:=ib+1;
       '''end'''  
       '''end'''  
       '''else''' '''begin'''
       '''else''' '''begin'''
           write(A{ia], ' ');
           write(A[ia], ' ');
           ia:=ia+1;
           ia:=ia+1;
           ib:=ib+1;
           ib:=ib+1;
Linia 569: Linia 661:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_6_2.html|Wizualizacja]]
</div>
</div>
</div>
</div>
Linia 574: Linia 669:
== Zadanie 7 (Podciąg) ==
== Zadanie 7 (Podciąg) ==
Dane są dwie tablice A typu array[1..N] of integer i B typu array[1..M] of integer, N, M > 0. Napisz program sprawdzający, czy A jest podciągiem B (tzn. czy istnieje funkcja f, rosnąca, z 1..N w 1..M, t. ze A[i]=B[f(i)]).
Dane są dwie tablice A typu array[1..N] of integer i B typu array[1..M] of integer, N, M > 0. Napisz program sprawdzający, czy A jest podciągiem B (tzn. czy istnieje funkcja f, rosnąca, z 1..N w 1..M, t. ze A[i]=B[f(i)]).
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1'''  <div class="mw-collapsible-content" style="display:none">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
Każdy element tablcy A musi odnależć swoją kopię w tablicy B. Przechodząc tablicę A od lewej do prawej i szukamy odpowiednika A[i] w części B, która jeszcze nie została odwiedzona.   
<div class="mw-collapsible-content" style="display:none">
Każdy element tablicy A musi odnaleźć swoją kopię w tablicy B. Przechodząc tablicę A od lewej do prawej i szukamy odpowiednika A[i] w części B, która jeszcze nie została odwiedzona.   
</div>
</div>
</div>
</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">
  '''program''' Podciąg(N,M:integer; A:array[1..N] of integer; B:array[1..M] of integer);
  '''program''' Podciąg(N,M:integer; A:array[1..N] of integer; B:array[1..M] of integer);
Linia 590: Linia 688:
     ia:=1;ib:=1;
     ia:=1;ib:=1;
     '''while''' (ia <= N) '''and''' (ib <= M) '''do'''
     '''while''' (ia <= N) '''and''' (ib <= M) '''do'''
       '''if''' A[ia] <> B[ib] '''then''' ib:=ib+1;
       '''if''' A[ia] <> B[ib] '''then''' ib:=ib+1
       '''else''' '''begin'''
       '''else''' '''begin'''
         ia:=ia+1;
         ia:=ia+1;
Linia 596: Linia 694:
       '''end''';
       '''end''';
     istnieje:=(ia>N);
     istnieje:=(ia>N);
     '''if''' istnieje '''then''' write('Tablica A jest podciągiem tablicy B);
     '''if''' istnieje '''then''' write('Tablica A jest podciągiem tablicy B');
   '''end''';
   '''end''';
  '''end'''.
  '''end'''.
Linia 602: Linia 700:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_7_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>
Linia 607: Linia 708:
== Zadanie 8 (Odwracanie tablicy) ==
== Zadanie 8 (Odwracanie tablicy) ==
Dana tablica A typu array[0..N-1] of integer, N > 1. Napisz program odwracający kolejność elementów w A.
Dana tablica A typu array[0..N-1] of integer, N > 1. Napisz program odwracający kolejność elementów w A.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1'''  <div class="mw-collapsible-content" style="display:none">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
Należy zamienić element 0 z N-1, 2 z N-2 itd.
<div class="mw-collapsible-content" style="display:none">
Należy zamienić element 0 z N-1, 1 z N-2 itd.
</div>
</div>
</div>
</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">
  '''program''' Odwracanie1(N:integer; A:array[0..N-1] of integer);
  '''program''' Odwracanie1(N:integer; A:array[0..N-1] of integer);
Linia 621: Linia 725:
   '''while''' l < (N div 2) '''do''' '''begin'''
   '''while''' l < (N div 2) '''do''' '''begin'''
     pom:=A[l];
     pom:=A[l];
     A[p]:=A[N-1-l];
     A[l]:=A[N-1-l];
     A[N-1-l]:=pom;
     A[N-1-l]:=pom;
     l:=l+1;
     l:=l+1;
Linia 629: Linia 733:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_8_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 2'''  <div class="mw-collapsible-content" style="display:none">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span>
To samo co w Rozwiązaniu 1 można zrobić używjąc dwóch indeksów l i p na oznaczenie elemnetów z lewej i prawej strony tablicy. W ten sposób na pewno nie pomylimy się wyliczając element z którym ma się zamienić l (czy to N-1-l, N-l, N-(l+1) itp.) i warunek w while.
<div class="mw-collapsible-content" style="display:none">
To samo co w Rozwiązaniu 1 można zrobić używjąc dwóch indeksów l i p na oznaczenie elemnetów z lewej i prawej strony tablicy. W ten sposób na pewno nie pomylimy się wyliczając element, z którym ma się zamienić l (czy to N-1-l, N-l, N-(l+1) itp.) i warunek w while.
</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 2</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' Odwracanie2(N:integer; A:array[0..N-1] of integer);
  '''program''' Odwracanie2(N:integer; A:array[0..N-1] of integer);
Linia 655: Linia 765:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_8_2.html|Wizualizacja]]


Można też odwracać jedynie część tablicy, pomiędzy indeksami l i p. Zapiszmy to w formie procedury
Można też odwracać jedynie część tablicy, pomiędzy indeksami l i p. Zapiszmy to w formie procedury
Linia 673: Linia 785:
== Zadanie 9 (Przesunięcie cykliczne) ==
== Zadanie 9 (Przesunięcie cykliczne) ==
Dana tablica A typu array[0..N-1] of integer, N > 1, i liczba naturalna k > 1. Napisz program realizujący przesunięcie cykliczne w prawo o k pól, czyli przesuwający zawartość pola A[i] na A[(i+k) mod N] dla każdego i < N.
Dana tablica A typu array[0..N-1] of integer, N > 1, i liczba naturalna k > 1. Napisz program realizujący przesunięcie cykliczne w prawo o k pól, czyli przesuwający zawartość pola A[i] na A[(i+k) mod N] dla każdego i < N.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 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">
Najprościej rozwiązać to zadanie używając dodatkowej pamięci rozmiaru N.
Najprościej rozwiązać to zadanie używając dodatkowej pamięci rozmiaru N.
Linia 680: Linia 793:
</div>
</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">
  '''program''' Przesuń1(N,k:integer; A:array[1..N] of integer);
  '''program''' Przesuń1(N,k:integer; A:array[0..N-1] of integer);
  '''var''' i: integer;
  '''var''' i: integer;
   P: array[0..N-1] of integer;
   P: array[0..N-1] of integer;
  '''begin'''
  '''begin'''
   '''for'' i:=0 '''to''' N-1 '''do''' P[(i+k) '''mod''' N]:=A[i];
   '''for''' i:=0 '''to''' N-1 '''do''' P[(i+k) '''mod''' N]:=A[i];
   '''for'' i:=0 '''to''' N-1 '''do''' A[i]:=P[i];
   '''for''' i:=0 '''to''' N-1 '''do''' A[i]:=P[i];
  '''end'''.
  '''end'''.
''Koszt czasowy'': liniowy względem N
''Koszt czasowy'': liniowy względem N


''Koszt pamięciowy'': liniowy względem N
''Koszt pamięciowy'': liniowy względem N
[[pimp:modul2_9_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 2''' 
<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">
<div class="mw-collapsible-content" style="display:none">
Można też skorzystać z rozkladu permutacji na cykle. Długość każdego takiego cyklu wynosi N/nwd(N,k) a na dodatek pierwsze nwd(N,k) elementów tablicy należy do różnych cykli. Dodatkowym kosztem jest oczywiście obliczenie nwd.  
Można też skorzystać z rozkładu permutacji na cykle. Długość każdego takiego cyklu wynosi N/nwd(N,k), a na dodatek pierwsze nwd(N,k) elementów tablicy należy do różnych cykli. Dodatkowym kosztem jest oczywiście obliczenie nwd.  
</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 2</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' Przesuń2(N,k:integer; A:array[1..N] of integer);
  '''program''' Przesuń2(N,k:integer; A:array[0..N-1] of integer);
  // k > 1
  // k > 1
  '''var''' dl_cyklu,ile_cykli: integer;
  '''var''' dl_cyklu,ile_cykli: integer;
Linia 715: Linia 834:
       pom:=A[nast];       //wstawiamy akt na A[nast]
       pom:=A[nast];       //wstawiamy akt na A[nast]
       A[nast]:=akt;
       A[nast]:=akt;
       akt:=pom;                       //to co tam było będzie nowym akt
       akt:=pom;                       //to co tam było, będzie nowym akt
       nast:=(nast+k) '''mod''' N;            //obliczamy nowe nast
       nast:=(nast+k) '''mod''' N;            //obliczamy nowe nast
     '''end''';
     '''end''';
Linia 725: Linia 844:
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 3''' 
<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">
<div class="mw-collapsible-content" style="display:none">
Można też zauważyć, że przesunięcie cykliczne o k w prawo można zrealizować poprzez trzy odwrócenia pewnych segmentów tablicy.
Można też zauważyć, że przesunięcie cykliczne o k w prawo można zrealizować poprzez trzy odwrócenia pewnych segmentów tablicy.
</div>
</div>
</div>
</div>
<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">Rozwiązanie 3</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' Przesun3(N,k:integer; A:array[1..N] of integer);
  '''program''' Przesun3(N,k:integer; A:array[0..N-1] of integer);
  // k > 1
  // k > 1
  '''begin'''
  '''begin'''
Linia 741: Linia 863:
   OdwracanieTablicy(A,0,N-1);
   OdwracanieTablicy(A,0,N-1);
  '''end'''.
  '''end'''.
Procedura OdwracanieTablicy pochodzi z Zadania 8. Poprawność tego rozwiązania można uzasadnić poniższym rysunekiem. W pierwszej linii jest aryginalna tablica, a w kolejnych tablica po kolejnych wywolaniach procedury OdwracanieTablicy.
Procedura OdwracanieTablicy pochodzi z Zadania 8. Poprawność tego rozwiązania można uzasadnić poniższym rysunekiem. W pierwszej linii jest oryginalna tablica, a w kolejnych tablica po kolejnych wywołaniach procedury OdwracanieTablicy.
   a(0)    a(1)    ...        ...    a(N-k-1) a(N-k)    ...        a(N-1)
   a(0)    a(1)    ...        ...    a(N-k-1) a(N-k)    ...        a(N-1)
  a(N-k-1) a(N-k-2)  ...        ...    a(0)    a(N-k)    ...        a(N-1)
  a(N-k-1) a(N-k-2)  ...        ...    a(0)    a(N-k)    ...        a(N-1)
Linia 750: Linia 872:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_9_3.html|Wizualizacja]]
</div>
</div>
</div>
</div>


== Zadanie 10 (Następna permutacja) ==
== Zadanie 10 (Następna permutacja) ==
Tablica A typu array[1..N] of integer, N > 0, zawiera pewną permutację liczb 1.. N. Napisz program wpisujący do A następną leksykograficznie [[permutację]]. Zakładamy, że permutacja w A nie jest ostatnia leksykograficznie.
Tablica A typu array[1..N] of integer, N > 0, zawiera pewną permutację liczb 1.. N. Napisz program wpisujący do A następną leksykograficznie [[permutację]]. Zakładamy, że permutacja w A nie jest ostatnia leksykograficznie.


'''Przykład''' Dla N=3 kolejne permutacje w [[porządku leksykograficznym]] wyglądają nastepująco:
'''Przykład''' Dla N=3 kolejne permutacje w [[porządku leksykograficznym]] wyglądają następująco:
  1 2 3
  1 2 3
  1 3 2
  1 3 2
Linia 763: Linia 888:
  3 1 2
  3 1 2
  3 2 1
  3 2 1
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 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">
Zastanów się która część talicy pozostanie taka sama w następnej permutacji.
Zastanów się, która część tablicy pozostanie taka sama w następnej permutacji.
</div>
</div>
</div>
</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ąznie 1</span>
<div class="mw-collapsible-content" style="display:none">  
<div class="mw-collapsible-content" style="display:none">
  '''program''' NastępnaPermutacja(N:integer; A:array[1..N] of integer);
  '''program''' NastępnaPermutacja(N:integer; A:array[1..N] of integer);
  //Permutacja zapisana w A nie jest ostatnia leksykograficznie
  //Permutacja zapisana w A nie jest ostatnia leksykograficznie
Linia 777: Linia 904:
  '''begin'''
  '''begin'''
   i:=N-1;
   i:=N-1;
   '''while''' i >= 1 '''do''' '''if''' A[i] > A[i+1] '''then''' i:=i-1;
   '''while''' A[i] > A[i+1] '''do''' i:=i-1;
   '''if''' i >= 1 '''then''' '''begin'''
   k:=N;
    k:=N;
  '''while''' A[k] < A[i] '''do''' k:=k-1;
    '''while''' k >= i '''do''' '''if''' A[k] < A[i] '''then''' k:=k-1;
  pom:=A[i];
    pom:=A[i];
  A[i]:=A[k];
    A[i]:=A[k];
  A[k]:=pom;
    A[k]:=pom;
  OdwracanieTablicy(A,i+1,N);
    OdwracanieTablicy(A,i,N);
   '''end''';
   '''end''';
  '''end'''.
  '''end'''.
Procedura OdwracanieTablicy pochodzi z Zadania 8.
Procedura OdwracanieTablicy pochodzi z Zadania 8.


Najpierw szukamy od tyłu pierwszego elementu, takiego że A[i] < A[i+1] (tu korzystamy z założenia że to nie ostatnia permutacja), potem szukamy na prawo od i najmniejszego większego od niego elementu k (uwaga: dużo wygodniej to robić od prawej strony!), potem zamieniamy te elementy i odwracamy kolejność elementów na prawo od i.
Najpierw szukamy od tyłu pierwszego elementu, takiego że A[i] < A[i+1] (tu korzystamy z założenia, że to nie ostatnia permutacja), potem szukamy na prawo od i najmniejszego większego od niego elementu k (uwaga: dużo wygodniej to robić od prawej strony!), potem zamieniamy te elementy i odwracamy kolejność elementów na prawo od i.


''Koszt czasowy'': liniowy względem N
''Koszt czasowy'': liniowy względem N


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_10_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>


== Zadanie 11 (Segment o danej sumie)  ==
== Zadanie 11 (Segment o danej sumie)  ==
Tablica A typu array[1..N] of integer, N > 0,  zawiera tylko liczby dodatnie. Napisz program który dla danego W typu integer sprawdza czy w A istnieje segment o sumie W (czyli czy istnieją l, p takie, że W<math>=A[l]+...+A[p-1]</math>).
Tablica A typu array[1..N] of integer, N > 0,  zawiera tylko liczby dodatnie. Napisz program, który dla danego W typu integer sprawdza, czy w A istnieje segment o sumie W (czyli czy istnieją l, p takie, że W<math>=A[l]+...+A[p-1]</math>).
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 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">
Podobnie jak w zadaniu o segmencie o maksymalnej sumie można dla  
Podobnie jak w zadaniu o segmencie o maksymalnej sumie można dla  
danego początku l obliczać po kolei sumy coraz dłuższych segmentów zaczynających sie w l.
danego początku l obliczać po kolei sumy coraz dłuższych segmentów zaczynających się w l.
</div>
</div>
</div>
</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">
  '''program''' SegmentODanejSumie1(N,W:integer; A:array[1..N] of integer);
  '''program''' SegmentODanejSumie1(N,W:integer; A:array[1..N] of integer);
Linia 816: Linia 947:
   '''if''' W < 0 '''then''' znalezione:=false  
   '''if''' W < 0 '''then''' znalezione:=false  
   '''else''' '''begin'''
   '''else''' '''begin'''
    maks:=0;
     l:=1;
     l:=1;
     znalezione:=false;
     znalezione:=false;
Linia 830: Linia 960:
     '''end''';  //while
     '''end''';  //while
   '''end''';  //else
   '''end''';  //else
   '''if''' znalezione '''then''' write('W tablicy A istnieje segment o sumie W);  
   '''if''' znalezione '''then''' write('W tablicy A istnieje segment o sumie W');  
  '''end'''.
  '''end'''.
''Koszt czasowy'': kwadratowy względem N
''Koszt czasowy'': kwadratowy względem N


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_11_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 2''' 
<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">
<div class="mw-collapsible-content" style="display:none">
Podobnie jak w zadaniu o segmencie o maksymalnej sumie możliwe też jest rozwiązanie o liniowym koszcie czasowym.
Podobnie jak w zadaniu o segmencie o maksymalnej sumie, możliwe też jest rozwiązanie o liniowym koszcie czasowym.
</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 2</span>
<div class="mw-collapsible-content" style="display:none">  
<div class="mw-collapsible-content" style="display:none">
  '''program''' SegmentODanejSumie2(N,W:integer; A:array[1..N] of integer);
  '''program''' SegmentODanejSumie2(N,W:integer; A:array[1..N] of integer);
  //Tablica A zawiera tylko liczby dodatnie
  //Tablica A zawiera tylko liczby dodatnie
Linia 856: Linia 992:
     suma:=0;
     suma:=0;
     '''while''' (suma <> W) '''and''' (p <= N) '''do'''
     '''while''' (suma <> W) '''and''' (p <= N) '''do'''
       '''if''' suma < W '''then''' '''begin''' //jeśli suma jest za mała to przesuwamy prawy koniec segmentu
       '''if''' suma < W '''then''' '''begin''' //jeśli suma jest za mała, to przesuwamy prawy koniec segmentu
         suma:=suma+A[p];
         suma:=suma+A[p];
         p:=p+1;
         p:=p+1;
       '''end'''
       '''end'''
       '''else''' '''begin''' //jeśli za duża to przesuwamy lewy koniec segmentu
       '''else''' '''begin''' //jeśli za duża, to przesuwamy lewy koniec segmentu
         suma:= suma-A[l];
         suma:= suma-A[l];
         l:=l+1;
         l:=l+1;
       '''end''';
       '''end''';
     '''while''' (suma > W) '''do''' '''begin'''          //jeśli suma nadal za duża to próbujemy ją zmniejszyć
     '''while''' (suma > W) '''do''' '''begin'''          //jeśli suma nadal za duża, to próbujemy ją zmniejszyć
       suma:= suma-A[l];
       suma:= suma-A[l];
       l:=l-1;
       l:=l+1;
     '''end''';
     '''end''';
     znalezione:=(suma=W);
     znalezione:=(suma=W);
   '''end''';  //else
   '''end''';  //else
   '''if''' znalezione '''then''' write('W tablicy A istnieje segment o sumie W);  
   '''if''' znalezione '''then''' write('W tablicy A istnieje segment o sumie W');  
  '''end'''.
  '''end'''.
Ponieważ jest to rozwiązanie działające w czasie liniowym od N (l+p zwiększa się w każdym obrocie pętli) a wszystkich segmentów jest kwadratowo wiele, powstaje wątpliwość czy przypadkiem nie omijamy
Ponieważ jest to rozwiązanie działające w czasie liniowym od N (l+p zwiększa się w każdym obrocie pętli), a wszystkich segmentów jest kwadratowo wiele, powstaje wątpliwość, czy przypadkiem nie omijamy
segmentu a maksymalnej sumie. To trzeba by udowodnić. Wrócimy do tego problemu w module o niezmiennikach i logice Hoare'a.
segmentu o maksymalnej sumie. To trzeba by udowodnić. Wrócimy do tego problemu w module o niezmiennikach i logice Hoare'a.


''Koszt czasowy'': liniowy względem N
''Koszt czasowy'': liniowy względem N


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_11_2.html|Wizualizacja]]
</div>
</div>
</div>
</div>


== Zadanie 12 (Głosowanie większościowe) ==
== Zadanie 12 (Głosowanie większościowe) ==
Dana jest tablica A typu array[1..N] of integer, N > 0. Sprawdzić czy jest w niej element wystepujący więcej niż N/2 razy i jeśli tak wskaż go.
Dana jest tablica A typu array[1..N] of integer, N > 0. Sprawdź, czy jest w niej element wystepujący więcej niż N/2 razy i jeśli tak - wskaż go.
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 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">
Najprościej jest dla każdego elementu policzyć liczbę wystąpień w tablicy. Jest to oczywiście rozwiązanie o kwadratowym koszcie czasowym.
Najprościej jest dla każdego elementu policzyć liczbę wystąpień w tablicy. Jest to oczywiście rozwiązanie o kwadratowym koszcie czasowym.
</div>
</div>
</div>
</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ąznie 1</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' Głosowanie1(N:integer; A:array[1..N] of integer);
  '''program''' Głosowanie1(N:integer; A:array[1..N] of integer);
{Program wypisuje wartość tego elementu, który występuje ponad połowę
razy, o ile taki istnieje, lub komunikat, że takiego elementu nie ma}
  '''var''' i,j,ile,indeks_lidera: integer;
  '''var''' i,j,ile,indeks_lidera: integer;
  '''begin'''
  '''begin'''
   i:=1;
   i:=1;
   indeks_lidera:=0;
   indeks_lidera:=0; {Zero oznacza, że lidera jeszcze nie znaleźliśmy}
   '''while''' (i < (N+1) div 2) '''and''' (indeks_lidera=0) '''do''' '''begin'''
   '''while''' (i < (N+1) div 2) '''and''' (indeks_lidera=0) '''do''' '''begin'''
     ile:=0;
     ile:=0;
     '''for j:=1 '''to''' N '''do''' if A[i]=A[j] '''then''' ile:=ile+1;
     '''for j:=i '''to''' N '''do''' if A[i]=A[j] '''then''' ile:=ile+1;
     '''if''' (ile >= N div 2 + 1) '''then''' indeks_lidera:=i;
    {Tutaj zaczynamy od i, bo nie ma sensu zaczynać wcześniej. I tak, jeśli istnieje lider,
      to będzie wykryty przy pierwszym jego wystąpieniu}
     '''if''' (ile >= N div 2 + 1) '''then''' indeks_lidera:=i
    '''else''' i:=i+1
   '''end''';
   '''end''';
   '''if''' indeks_lidera <> 0 '''then''' write('Liderem jest: ', A[indeks_lidera]);
   '''if''' indeks_lidera <> 0 '''then''' write('Liderem jest: ', A[indeks_lidera])
  '''else''' write('Nie ma lidera')
  '''end'''.
  '''end'''.
Ponieważ lider musi mieć co najmiej N div 2 + 1 wystąpień w tablicy, to wystarczy go szukać na ((N+1) div 2) pierwszych pozycjach tablicy A.
Ponieważ lider musi mieć co najmiej N div 2 + 1 wystąpień w tablicy, to wystarczy go szukać na ((N+1) div 2) pierwszych pozycjach tablicy A.
Linia 910: Linia 1055:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_12_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 2''' 
<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">
<div class="mw-collapsible-content" style="display:none">
To zadanie ma też (piękne) rozwiązanie liniowe. Składa się ono z dwóch faz. W pierwszej wyznaczamy takie kand, że jeśli jest lider, to jest nim kand, w drugiej (banalnej) sprawdzamy czy kand wygrał.
To zadanie ma też (piękne) rozwiązanie liniowe. Składa się ono z dwóch faz. W pierwszej wyznaczamy takie kand, że jeśli jest lider, to jest nim kand; w drugiej (banalnej) sprawdzamy, czy kand wygrał.
</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 2</span>
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">
  '''program''' Głosowanie2(N,W:integer; A:array[1..N] of integer);
  '''program''' Głosowanie2(N:integer; A:array[1..N] of integer);
  '''var''' ile,i,kand,lider: integer;
  '''var''' ile,i,kand,lider: integer;
  '''begin'''
  '''begin'''
Linia 936: Linia 1086:
       '''end''';
       '''end''';
   '''end''';
   '''end''';
   ile:=0; //sprawdzamy czy kandydat jest liderem
   ile:=0; //sprawdzamy, czy kandydat jest liderem
   '''for''' i:=1 '''to''' '''do'''  
   '''for''' i:=1 '''to''' N '''do'''  
     '''if''' A[i]=kand '''then''' ile:=ile+1;  
     '''if''' A[i]=kand '''then''' ile:=ile+1;  
   '''if''' (ile >= (N div 2 + 1) '''then''' '''begin'''  
   '''if''' (ile >= (N div 2 + 1)) '''then''' '''begin'''  
     lider:=kand;
     lider:=kand;
     write('Liderem jest: ', kand);
     write('Liderem jest: ', kand);
Linia 949: Linia 1099:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
[[pimp:modul2_12_2.html|Wizualizacja]]
</div>
</div>
</div>
</div>
Linia 954: Linia 1107:
== Zadanie 13 (Arytmetyka liczb wielocyfrowych) ==
== Zadanie 13 (Arytmetyka liczb wielocyfrowych) ==
Liczby wielocyfrowe będą reprezentowane w tablicach typu liczba=array[0..N-1] of integer, N > 1, w taki sposób, że najmniej znacząca cyfra jest pod indeksem 0. Rozpatrujemy liczby przy podstawie b > 1. Napisz procedury obliczające:
Liczby wielocyfrowe będą reprezentowane w tablicach typu liczba=array[0..N-1] of integer, N > 1, w taki sposób, że najmniej znacząca cyfra jest pod indeksem 0. Rozpatrujemy liczby przy podstawie b > 1. Napisz procedury obliczające:
# sumę liczb A i B do C. Jeśli wynik nie zmieści się w C to wartość C nie ma znaczenia. Zmienna przepełnienie wskazuje czy do niego doszło czy nie.
# sumę liczb A i B do C. Jeśli wynik nie zmieści się w C, to wartość C nie ma znaczenia. Zmienna przepełnienie wskazuje czy do niego doszło czy nie.
# różnicę A i B do C. Jeśli wynik miałby byc liczbą ujemną to wartość C nie ma znaczenia. Zmienna ujemny wskazuje jaki jest znak wyniku.
# różnicę A i B do C. Jeśli wynik miałby byc liczbą ujemną, to wartość C nie ma znaczenia. Zmienna ujemny wskazuje jaki jest znak wyniku.
# iloczyn A i B do C (C powinno być tablicą dwa razy dłuższą niż A i B, żeby móc pomieścić wynik).  
# iloczyn A i B do C (C powinno być tablicą dwa razy dłuższą niż A i B, żeby móc pomieścić wynik).  


<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">
  '''const''' N=100;  
  '''const''' N=100;  
   b=10;  
   b=10;  
Linia 968: Linia 1121:
Poniżej treści procedur Suma, Roznica, Iloczyn:
Poniżej treści procedur Suma, Roznica, Iloczyn:
   
   
  '''procedure''' Suma(A,B:liczba, var C:liczba, var:przepełnienie:boolean);
  '''procedure''' Suma(A,B:liczba, var C:liczba, var przepełnienie:boolean);
  //Sumujemy liczby zapisane w A i B do C; zmienna przepełnienie staje się true gdy wynik nie mieści się w C.
  //Sumujemy liczby zapisane w A i B do C; zmienna przepełnienie staje się true, gdy wynik nie mieści się w C.
  '''var''' p: integer;
  '''var''' p: integer;
  '''begin'''
  '''begin'''
Linia 986: Linia 1139:


''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
  '''procedure''' Różnica(A,B:liczba, var C:liczba, var:ujemny:boolean);
  '''procedure''' Różnica(A,B:liczba, var C:liczba, var ujemny:boolean);
  //Odejmujemy od liczby zapisanej w A liczbę z B. Wynik zapisujemy w C, zmienna ujemny informuje o znaku wyniku.
  //Odejmujemy od liczby zapisanej w A liczbę z B. Wynik zapisujemy w C, zmienna ujemny informuje o znaku wyniku.
  '''var''' p: integer;
  '''var''' p: integer;
Linia 1011: Linia 1164:
   '''for''' i:=0 '''to''' 2*N-1 '''do''' C[i]:=0;
   '''for''' i:=0 '''to''' 2*N-1 '''do''' C[i]:=0;
   '''for''' i:=0 '''to''' N-1 '''do''' '''begin'''
   '''for''' i:=0 '''to''' N-1 '''do''' '''begin'''
     '''for''' j:=1 '''to''' N-1 '''do''' '''begin'''
     '''for''' j:=0 '''to''' N-1 '''do''' '''begin'''
       w:=A[i]*B[j]+p+C[i+j];
       w:=A[i]*B[j]+p+C[i+j];
       C[i+j]:=w '''mod''' b;
       C[i+j]:=w '''mod''' b;
Linia 1025: Linia 1178:
</div>
</div>
</div>
</div>
==Zadanie 1 (Labirynt)==
Czy istnieje ścieżka miedzy wskazanymi punktami (i1,j1) i (i2,j2) w labiryncie reprezentowanym przez prostokątną tablicę liczb całkowitych o rozmiarze M×N, zawierającą zera (ściana) i jedynki (droga)? Zakładamy, że nie można przechodzić z pola na pole po skosie (np. z (2,5) na (3,6)), a tylko w czterech podstawowych kierunkach (np. z (2,5) na (3,5), (2,4) itd.)
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1'''
<div class="mw-collapsible-content" style="display:none">
Właściwą funkcję rekurencyjną szukającą drogi zamknij w funkcji-otoczce, która poza wywołaniem funkcji rekurencyjnej sprawdzi poprawność argumentów, przygotuje i/lub posprząta tablicę z labiryntem, zinterpretuje wynik funkcji rekurencyjnej itp. oraz będzie przechowywać dane wspólne dla wszystkich wywołań funkcji rekurencyjnej.
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1'''
<div class="mw-collapsible-content" style="display:none">
'''function''' Labirynt(M,N:integer; '''var''' A:'''array'''[1..M,1..N] '''of''' integer; i1,j1,i2,j2:integer):boolean;
// M,N >= 1
// A zawiera 0 (ściana) i 1 (droga)
  '''function''' szukaj(i,j:integer):boolean;
  // 1 <= i <= M
  // 1 <= j <= N
  '''var''' jest:boolean;
  '''begin'''
    '''if''' (i=i2) '''and''' (j=j2) '''then'''
      jest:=true
    '''else''' '''begin'''
      jest:=false;
      '''if''' A[i,j]>0 '''then''' '''begin'''
        A[i,j]:=-1;
        '''if''' i>1 '''then''' jest:=szukaj(i-1,j);
        '''if''' '''not''' jest '''and''' (i<M) '''then''' jest:=szukaj(i+1,j);
        '''if''' '''not''' jest '''and''' (j>1) '''then''' jest:=szukaj(i,j-1);
        '''if''' '''not''' jest '''and''' (j<N) '''then''' jest:=szukaj(i,j+1);
      '''end'''
    '''end''';
    szukaj:=jest
  '''end'''; // szukaj
 
'''var''' i,j:integer;
'''begin''' // Labirynt
  '''if''' '''not'''((1<=i1) '''and''' (i1<=M) '''and''' (1<=j1) '''and''' (j1<=N) '''and'''
    (1<=i2) '''and''' (i2<=M) '''and''' (1<=j2) '''and''' (j2<=N)) '''then'''
    Labirynt:=false
  '''else'''
  '''begin'''
    Labirynt:=szukaj(i1,j1); 
    '''for''' i:=1 '''to''' M '''do'''
      '''for''' j:=1 '''to''' N '''do'''
        '''if''' A[i,j]=-1 '''then''' A[i,j]:=1
  '''end'''
'''end'''; // Labirynt
''Koszt czasowy:'' liniowy względem rozmiaru A (czyli M×N)
''Koszt pamięciowy:'' liniowy względem rozmiaru A
''Opis:'' [[Przeszukujemy wgłąb]] tablicę zaznaczając odwiedzone pola poprzez ustawienie ich wartości na -1. Dzięki temu nie zapętlimy się, ani nie przetwarzamy wielokrotnie tych samych pól.
''Dyskusja:'' Funkcja 'Labirynt' jest otoczką, która sprawdza poprawność parametrów, wywołuje właściwą funkcję rekurencyjną 'szukaj' oraz sprząta po niej zaznaczenia w tablicy A.
Wewnętrzna funkcja rekurencyjna 'szukaj' ma za zadanie znaleźć ścieżkę z punktu (i,j) do punktu (i2,j2) po niezaznaczonych polach w tablicy A. Korzysta ona z kilku nazw zadeklarowanych przez otoczkę (M, N, A, i2, j2), dlatego nie są one parametrami wywołania funkcji 'szukaj'.
Funkcja 'szukaj':
# sprawdza czy punkt (i,j) nie jest poszukiwanym końcem (w tym przypadku zwraca true),
# sprawdza czy punkt (i,j) nie jest ścianą lub punktem odwiedzonym wcześniej (w tym przypadku zwraca false),
# zaznacza punkt (i,j) jako odwiedzony
# próbuje szukać drogi z punktów sąsiednich dla punktu (i,j), o ile sąsiedzi Ci istnieją.
Zauważ, że testy 1 i 2, mogłyby być wykonane przed każdym wywołaniem funkcji 'szukaj' w punkcie 4 (oraz w otoczce) zamiast na jej początku, jednak prowadziłoby to do wielokrotnego pisania bardzo podobnych fragmentów programu, co łatwo prowadzi do błędów. Oczywiście nie zmniejszyłoby to złożoności czasowej i pamięciowej.
Podobnie, jak testy 1 i 2, testy istnienia sąsiadów (i>1), (i<M) itp. w punkcie 4 mogłyby być wykonane na początku funkcji 'szukaj' (wtedy nie zakładalibyśmy, że (i,j) jest poprawnym punktem w tablicy), ale nie mając wiedzy w którą stronę ostatnio poszliśmy, musielibyśmy dla sprawdzić pełną poprawność obu współrzędnych (i,j), czyli w sumie sprawdzalibyśmy 4 warunki. W aktualnej wersji sprawdzamy tylko 1 warunek.
''Poprawność rozwiązania:'' Oczywiste jest, że jeśli funkcja 'Labirynt' da wynik true, to ścieżka z (i1,j1) do (i2,j2) istnieje. Mniej oczywiste jest, że jeśli funkcja da wynik false, to ścieżka na pewno nie istnieje.
Aby przeprowadzić dowód przez sprzeczność, załóżmy, że funkcja 'szukaj' wywołana w funkcji 'Labirynt' dała wynik false, a ścieżka z (i1,j1) do (i2,j2) istnieje. W takim razie A[i1,j1]=-1 a A[i2,j2]=1. Wynika z tego, że ścieżka z (i1,j1) do (i2,j2) w którymś miejścu ''opuszcza'' zaznaczoną część tablicy, czyli istnieją dwa sąsiednie pola (i,j) i (i',j') na tej ścieżce, takie że A[i,j]=-1, A[i',j']=1. Z tego wynika, że funkcja szukaj została (w czasie działania programu) wywołana z parametrami (i,j), ale nie została wywołana z parametrami (i',j'). Jest to niemożliwe, bo pola te sąsiadują ze sobą i wywołanie dla (i,j) wywołałoby rekurencyjnie 'szukaj' dla (i',j').
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Pytanko 1:''' 
<div class="mw-collapsible-content" style="display:none"> Ile razy maksymalnie może być wywołana funkcja 'szukaj' dla tego samego punktu?
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Pytanko 2:''' 
<div class="mw-collapsible-content" style="display:none"> Jak przerobić przedstawione rozwiązanie na program wypisujący na ekran ścieżkę pomiędzy punktami (i1,j1) i (i2,j2), o ile taka ścieżka istnieje. Czy wypisana ścieżka będzie najkrótsza z możliwych ?
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Pytanko 3:''' (trudniejsze)
<div class="mw-collapsible-content" style="display:none">
Co by się stało, gdybyśmy usuwali zaznaczenie wychodząc z funkcji 'szukaj'? Czy program dalej by działał? Jeśli tak, to jaką by miał złożoność?
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Odpowiedź:'''
<div class="mw-collapsible-content" style="display:none">
Program dalej by działał, ale miałby wykładniczą złożoność czasową zamiast liniowej (złożoność pamięciowa pozostałaby liniowa). W tej wersji program wielokrotnie przeszukiwałby sąsiadów pól, o których już z wcześniejszych obliczeń wiadomo, że nie da się z nich dojść do punktu końcowego.
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Dla ciekawskich:'''
<div class="mw-collapsible-content" style="display:none">
Rozwiązanie przedstawione powyżej polega na [[przeszukiwaniu wgłąb]] grafu reprezentującego labirynt. Inne, równie dobre rozwiązanie polega na przeszukiwaniu tego grafu [[wszerz]], zwanego również [[metodą płonącego lasu]]. Wymaga ono użycia struktury danych -- [[kolejki]]. Rozwiązanie to łatwo przerobić na program wypisujący najkrótszą ścieżkę pomiędzy punktami (i1,j1) i (i2,j2), o ile taka ścieżka istnieje.
</div>
</div>
==Zadanie 2 (Z górki na pazurki)==
W tablicy liczb całkowitych o rozmiarze M&times;N zapisana jest mapa
gór (każdy punkt ma podaną dodatnią wysokość). Sprawdzić, czy da się
przejść z punktu startowego (i1,j1) do docelowego (i2,j2) idąc:
* tylko w dół lub po płaskim
* tylko w dół
Tak jak w poprzednim zadaniu poruszać się można tylko w czterech kierunkach podstawowych, nie po przekątnej.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1'''
<div class="mw-collapsible-content" style="display:none">
Zadanie to należy rozwiązywać tak jak poprzednie. Jedyną różnicą jest to jak należy decydować czy z danego pola można przejść do sąsiedniego: oprócz zaznaczenia trzeba wziąć pod uwagę różnicę wysokości.
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1'''
<div class="mw-collapsible-content" style="display:none">
'''function''' Zjazd1(M,N:integer; '''var''' A:'''array'''[1..M,1..N] '''of''' integer; i1,j1,i2,j2:integer):boolean;
// M,N >= 1
// A zawiera liczby > 0
  '''function''' szukaj(h,i,j:integer):boolean;
  // 0 < h
  // 1 <= i <= M
  // 1 <= j <= N
  '''var''' jest:boolean;
    hpom:integer;
  '''begin'''
    jest:=false;
    '''if''' (A[i,j]>0) '''and''' (h>A[i,j]) '''begin''' // h>=A[i,j] w wariancie II
      '''if''' (i=i2) '''and''' (j=j2) '''then'''
        jest:=true
      '''else''' '''begin'''
        hpom:=A[i,j];
        A[i,j]:=-A[i,j];
        '''if''' i>1 '''then''' jest:=szukaj(hpom,i-1,j);
        '''if''' '''not''' jest '''and''' (i<M) '''then''' jest:=szukaj(hpom,i+1,j);
        '''if''' '''not''' jest '''and''' (j>1) '''then''' jest:=szukaj(hpom,i,j-1);
        '''if''' '''not''' jest '''and''' (j<N) '''then''' jest:=szukaj(hpom,i,j+1);
      '''end'''
    '''end''';
    szukaj:=jest
  '''end'''; // szukaj
 
'''var''' i,j:integer;
'''begin''' // Zjazd1
  '''if''' '''not'''((1<=i1) '''and''' (i1<=M) '''and''' (1<=j1) '''and''' (j1<=N) '''and'''
    (1<=i2) '''and''' (i2<=M) '''and''' (1<=j2) '''and''' (j2<=N)) '''then'''
    Zajzd:=false
  '''else'''
  '''begin'''
    Zjazd:=szukaj(A[i1,j1]+1,i1,j1); // wystarczy szukaj(A[i1,j1],i1,j1) w wariancie II
    '''for''' i:=1 '''to''' M '''do'''
      '''for''' j:=1 '''to''' N '''do'''
        '''if''' A[i,j]<0 '''then''' A[i,j]:=-A[i,j]
  '''end'''
'''end'''; // Zjazd1
''Koszt czasowy:'' liniowy względem rozmiaru A (czyli M×N)
''Koszt pamięciowy:'' liniowy względem rozmiaru A
''Opis:'' Podobnie jak w poprzednim zadaniu, przeszukujemy tablicę [[wgłąb]], jednak przechodzimy tylko do tych pól sąsiednich, które mają mniejszą (odpowiednio: mniejszą lub równą) wysokość.
''Dyskusja:'' Tak jak w rozwiązaniu poprzedniego zadania, istnienie sąsiada na planszy badamy przed wywołaniem rekurencyjnym, a poprawność przejścia na początku wywołania. Służy nam do tego dodatkowy parametr 'h', który oznacza wysokość poprzedniego pola. Dlatego pierwsze wywołanie funkcji 'szukaj' ma pierwszy parametr A[i1,j1]+1 (w wariancie I). '''Uwaga!''' Funkcja ta nie zadziała, jeśli A[i1,j1]=MaxInt (czyli maksymalnej możliwej wartości typu integer). Poniżej przedstawione jest rozwiązanie bez tego mankamentu.
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 2'''
<div class="mw-collapsible-content" style="display:none">
'''function''' Zjazd2(M,N:integer; '''var''' A:'''array'''[1..M,1..N] '''of''' integer; i1,j1,i2,j2:integer):boolean;
// M,N >= 1
// A zawiera liczby > 0
  '''function''' wdol(h,i,j:integer):boolean;
  // sprawdza czy pole (i,j) nie jest zaznaczone i
  // czy przejscie z pola o wysokosci h na pole (i,j) jest rzeczywiscie w dół
  // 1 <= i <= M
  // 1 <= j <= N
  '''begin'''
    wdol:=(A[i,j]>0) '''and''' (h>A[i,j]) // h>=A[i,j] w wariancie II
  '''end'''; //wdol
  '''function''' szukaj(i,j:integer):boolean;
  // 1 <= i <= M
  // 1 <= j <= N
  '''var''' jest:boolean;
    hpom:integer;
  '''begin'''
    '''if''' (i=i2) '''and''' (j=j2) '''then'''
      jest:=true
    '''else''' '''begin'''
      jest:=false;
      hpom:=A[i,j];
      A[i,j]:=-hpom;
      '''if''' i>1 '''then''' '''if''' wdol(hpom,i-1,j) '''then''' jest:=szukaj(i-1,j);
      '''if''' '''not''' jest '''and''' (i<M) '''then''' '''if''' wdol(hpom,i+1,j) '''then''' jest:=szukaj(i+1,j);
      '''if''' '''not''' jest '''and''' (j>1) '''then''' '''if''' wdol(hpom,i,j-1) '''then''' jest:=szukaj(i,j-1);
      '''if''' '''not''' jest '''and''' (j<N) '''then''' '''if''' wdol(hpom,i,j+1) '''then''' jest:=szukaj(i,j+1);
    '''end''';
    szukaj:=jest
  '''end'''; // szukaj
 
'''var''' i,j:integer;
'''begin''' // Zjazd2
  '''if''' '''not'''((1<=i1) '''and''' (i1<=M) '''and''' (1<=j1) '''and''' (j1<=N) '''and'''
    (1<=i2) '''and''' (i2<=M) '''and''' (1<=j2) '''and''' (j2<=N)) '''then'''
    Zajzd:=false
  '''else'''
  '''begin'''
    Zjazd:=szukaj(i1,j1);
    '''for''' i:=1 '''to''' M '''do'''
      '''for''' j:=1 '''to''' N '''do'''
        '''if''' A[i,j]<0 '''then''' A[i,j]:=-A[i,j]
  '''end'''
'''end'''; // Zjazd2
''Koszt czasowy:'' liniowy względem rozmiaru A (czyli M×N)
''Koszt pamięciowy:'' liniowy względem rozmiaru A
''Opis:'' Rozwiązanie jest bardzo podobne do poprzedniego. Różnica polega na przeniesieniu kodu z początku funkcji 'szukaj' do osobnej funkcji 'wdol'. Funkcja ta jest używana jako test dopuszczający do rekurencyjnego wywołania funkcji 'szukaj'.
</div>
</div>
==Zadanie 3 (Wieże Hanoi z ograniczeniami)==
Na wykładzie były [[wieże Hanoi]]. Ciekawa modyfikacja tego zadania polega na zabronieniu ruchów pomiędzy niektórymi pałeczkami, np. z pierwszej na drugą. Zapisać procedurę realizującą to zadanie przy zabronionych niektórych ruchach.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1'''
<div class="mw-collapsible-content" style="display:none">
* Dozwolone ruchy najlepiej reprezentować w tablicy typu TDozwRuchow = array[1..3, 1..3] of boolean, (przekątna nie ma znaczenia).
* Zastanów się, jaki warunek musi być spełniony przez tablicę dozwolonych ruchów, aby zadanie miało rozwiązanie.
* Użyj funkcji-otoczki do wstępnego sprawdzenia czy istnieje rozwiązanie oraz do pamiętania tablicy dozwolonych ruchów w czasie działania funkcji rekurencyjnej.
</div>
</div>
<!-- 
procedure Przenies(Skad, Dokad: Paleczki);
begin
writeln('Przenoszę krążek z ',Skad',' na ',Dokad);
end;
-->
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1'''
<div class="mw-collapsible-content" style="display:none">
'''type''' Paleczki = 1..3;
'''procedure''' Hanoi(Ile: integer; Skad, Dokad: Paleczki; Dozw: TDozwRuchow);
  '''procedure''' Rob(Skad, Dokad, Pom: Paleczki; Ile: Integer);
  // Pom jest zawsze rowne 6-Skad-Dokad, ale z parametrem jest czytelniej
  '''begin'''
    '''if''' Ile > 0 '''then'''
      '''if''' Dozw[Skad, Dokad] '''then''' '''begin'''
        Rob(Skad, Pom, Dokad, Ile-1);
        Przenies(Skad,Dokad);
        Rob(Pom, Dokad, Skad, Ile-1);
      '''end'''
      '''else''' '''begin'''
        Rob(Skad, Dokad, Pom, Ile-1);
        Przenies(Skad, Pom);
        Rob(Dokad, Skad, Pom, Ile-1);
        Przenies(Pom, Dokad);
        Rob(Skad, Dokad, Pom, Ile-1);
      '''end'''
  '''end'''; //Rob
  '''function''' CzyDaSie(Skad, Dokad, Pom: Paleczki):boolean
  '''begin'''
    '''if''' '''not''' Dozw[Skad, Dokad] '''and''' '''not''' (Dozw[Skad, Pom] '''and''' Dozw[Pom, Dokad]) '''then''' '''begin'''
      writeln('Nie da sie przełożyć krążka z ',Skad,' na ',Pom);
      CzyDaSie:=false
    '''end'''
    '''else'''
      CzyDaSie:=false
  '''end''' // CzyDaSie   
'''var''' ok:boolean
'''begin''' // Hanoi
  ok:=true;
  '''for''' i:=1 '''to''' 2 '''do''' '''for''' j:=i+1 '''to''' 3 '''do'''
    ok:=ok '''and''' CzyDaSie(i,j,6-i-j) '''and''' CzyDaSie(j,i,6-i-j);
  '''if''' ok '''then''' Rob(Skad,Dokad,6-Skad-Dokad,Ile);
'''end'''; // Hanoi
''Koszt czasowy:'' wykładniczy ze względu na Ile
''Koszt pamięciowy:'' liniowy ze względu na Ile
''Omówienie:'' Zauważ, że dużo łatwiej jest rozwiązać to zadanie sformułowane w sposób ogólny, niż gdy powie się, że zabroniony jest konkretny ruch (np. 1 → 2).
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Pytanko 1'''
<div class="mw-collapsible-content" style="display:none">
Jaki przypadek jest najgorszy i ile trzeba wykonać wtedy ruchów?
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Odpowiedź'''
<div class="mw-collapsible-content" style="display:none">
Najgorszy przypadek, to taki, gdy przerwane jest połączenie Skąd-Dokąd w obie strony. Wtedy trzeba wykonać <math>3^{Ile}-1</math> ruchów)
</div>
</div>
==Zadanie 4 (Ustawianie hetmanów)==
Napisz procedurę znajdująca wszystkie takie rozstawienia 8 hetmanów na szachownicy, by żadne dwa hetmany się nie atakowały.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1'''
<div class="mw-collapsible-content" style="display:none">
W tablicach logicznych pamiętamy zajętość kolumn i obu rodzajów przekątnych, kolejnego hetmana ustawiamy w kolejnym wierszu jeśli się da, jeśli nie wracamy.
Rozwiązanie jest ładnie opisane w [[dużym Wirthcie]], str. 155-160.
Oczywiście lepiej uogólnić na N hetmanów na szachownicy N×N.
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1'''
<div class="mw-collapsible-content" style="display:none">
'''procedure''' Hetmany(N:integer);
// N >= 1
'''var'''
  wiersze:'''array'''[1..N] '''of''' integer;
  kolumny:'''array'''[1..N] '''of''' boolean;
  przekgd:'''array'''[-(N-1)..N-1] '''of''' boolean; // przekątne \ o stałej różnicy
  przekdg:'''array'''[2..2*N] '''of''' boolean;      // przekątne / o stałej sumie
 
  '''procedure''' ustaw(k,i:integer);
  // 1 <= k,i <= N
  '''begin'''
    wiersze[k]:=i;
    kolumny[i]:=true;
    przekgd[k-i]:=true; 
    przekdg[k+i]:=true; 
  '''end'''; // ustaw
 
  '''procedure''' odstaw(k,i:integer);
  // 1 <= k,i <= N
  '''begin'''
    wiersze[k]:=0;
    kolumny[i]:=false;
    przekgd[k-i]:=false; 
    przekdg[k+i]:=false; 
  '''end'''; // odstaw
   
  '''function''' wolne(k,i:integer):boolean
  // 1 <= k,i <= N
  '''begin'''
    wolne:='''not''' kolumny[i] & '''not''' przekgd[k-i] & '''not''' przekdg[k+i]
  '''end'''; // wolne
  '''var''' jest:boolean;
  '''procedure''' wypisz;
  '''var''' i:integer;
  '''begin'''
    jest:=true;
    write('Ustawienie: ')
    '''for''' i:=1 '''to''' N; '''do''' write(i,':',wiersze[i],' ')
    writeln;
  '''end'''; // wypisz
  '''procedure''' rozstaw(k:integer);
  '''var''' i:integer;
  '''begin'''
    '''if''' k=N+1 '''then'''
      wypisz
    '''else'''
      '''for''' i:=1 '''to''' N '''do'''
        '''if''' wolne(k,i) '''then''' '''begin'''
  ustaw(k,i);
  rozstaw(k+1);
  odstaw(k,i);
        '''end'''
  '''end'''; // rozstaw
'''var''' i:integer;
'''begin''' // Hetmany
  '''for''' i:=1 '''to''' N '''do''' wiersze[i]:=0;
  '''for''' i:=1 '''to''' N '''do''' kolumny[i]:=false;
  '''for''' i:=-(N-1) '''to''' N-1 '''do''' przekgd[i]:=false;
  '''for''' i:=2 '''to''' 2*N '''do''' przekdg[i]:=false;
  jest:=false;
  rozstaw(i);
  '''if''' '''not''' jest '''then''' writeln('Nie znaleziono żadnego ustawienia')
'''end''' // Hetmany
''Koszt czasowy:'' wykładniczy względem N
''Koszt pamięciowy:'' liniowy względem N
''Opis:'' Aby ustawić N hetmanów, każdy z nich musi stać w osobnym wierszu. Dlatego główna procedurą rekurencyjna 'rozstaw' próbuje ustawić k-tego hetmana w wierszu k w kolejnych kolumnach. Jeśli to się uda (wolne(k,i)=true) zaznacza zajętość odpowiedniej kolumny i przekątnych i wywołuje się rekurencyjnie aby rozstawić pozostałe hetmany. Po powrocie z wywołania rekurencyjnego, kolumna i przekątne są zwalniane i pętla for próbuje ustawić k-tego hetmana w kolejnej kolumnie.
Jeśli nie ma już żadnych hetmanów do rozstawiania (k=N+1) oznacza to, że N jest już ustawionych - pozostaje ich wypisać. Przy okazji zmienna 'jest' rejestruje czy jakiekolwiek rozwiązanie zostało wypisane. Jeśli nie, główna procedura 'Hetmany' wypisuje stosowny komunikat.
</div>
</div>
==Zadanie 5 (Mnożenie wielomianów)==
Dane są dwie tablice (array[0..N-1] of real) reprezentujące dwa wielomiany stopnia N-1. Należy obliczyć iloczyn tych wielomianów metodą dziel-i-zwyciężaj. Zakładamy, że N jest potęgą dwójki.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1'''
<div class="mw-collapsible-content" style="display:none">
Zamiast rozwiązania naiwnego wymajającego <math>n^2</math> mnożeń zróbmy trochę lepsze (aczkolwiek nie najlepsze) polegające na podzieleniu wielomianów na dwie części. Cały pomysł polega na spostrzeżeniu, że jeśli zadane wielomiany <math>p(x)</math> i <math>q(x)</math> podzielimy na dolna i górną część<br>
<math>p(x) = p_l(x) + p_h(x)*x^{N/2}</math> i analogicznie
<math>q(x) = q_l(x) + q_h(x)*x^{N/2}</math>, to ich iloczyn można zapisać tak:<br>
<math>p(x)*q(x) = r_l(x)+(r_m(x)-r_l(x)-r_h(x))*x^{N/2}+r_h(x)*x^N</math>, gdzie<br>
<math>r_l(x) = p_l(x)*q_l(x)</math><br>
<math>r_h(x) = p_h(x)*q_h(x)</math><br>
<math>r_m(x) = (p_h(x)+p_l(x))*(q_h(x)+q_l(x))</math><br>
Czyli potrzebujemy 3 mnożeń o połowę mniejszych wielomianów. W sumie uzyskamy liczbę mnożeń rzędu <math>n^{lg 3}</math>. Szczególy można znaleźć w [[Sedgewick|Sedgewick Algorithms in C++]], str. 527-530.
</div>
</div>
==Zadanie 6 (Suma składników)==
Napisz procedurę, która wypisze dla zadanej liczby n jej wszystkie rozkłady na sumy nieujemnych liczb naturalnych większych od 1 ustawionych w kolejności nierosnącej. Np. dla n = 3:<br>
3 = 3<br>
3 = 2+1<br>
3 = 1+1+1
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1'''
<div class="mw-collapsible-content" style="display:none">
Użyj dodatkowej tablicy do przechowywania początków rozkładów. Uważaj, aby nie kopiować tej tablicy przy każdym wywołaniu rekurencyjnym!
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 2'''
<div class="mw-collapsible-content" style="display:none">
Funkcja rekurencyjna powinna mieć parametr wskazujący jak duże składniki mogą być użyte do rozkładu pozostałej liczby. </div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie 1'''
<div class="mw-collapsible-content" style="display:none">
'''procedure''' Suma(n:integer);
// 1 <= n
  '''procedure''' rozklad('''var''' T:'''array'''[1..n] '''of''' integer; ti,k,m:integer)
  // 0 <= ti <= n
  // ti > 0 --> k=T[ti]
  // 0 <= m
  // m=0 --> ti > 0
  '''var''' i:integer
  '''begin'''
    '''if''' m=0 '''then''' '''begin'''
      writeln(n,' = ');
      '''for''' i=1 '''to''' ti-1 '''do''' write(T[i],'+');
      writeln(T[ti])
    '''end'''       
    '''else''' '''begin'''
      ti:=ti+1;
      '''for''' i=min(k,m) '''downto''' 1 '''do''' '''begin'''
        T[ti]:=i;
        rozklad(T,ti,i,m-i);
      '''end'''
    '''end'''
  '''end''' //rozklad
'''var''' T:'''array'''[1..n] '''of''' integer;
'''begin'''   
  rozklad(T,0,n,n);
'''end''' // Suma
''Koszt czasowy:'' wykładniczy względem n
''Koszt pamięciowy:'' liniowy względem n
''Opis:'' Funkcja rekurencyjna 'rozkład' przegląda wszystkie nierosnące rozkłady liczby m używające składników niewiększych niż k. Ponieważ w tablicy T[1..ti] jest już nierosnący ciąg składników o sumie n-m, wydłużenie go o dowolny taki rozkład m będzie dawać poprawny rozkład n.
Istotnie, jeśli m=0, w tablicy jest już gotowy rozkład n, więc wypisujemy go. W przeciwnym razie zwiekszamy ti, wszystkie liczby i, które mogą znaleźć się w tym miejscu rozkładu umieszczamy kolejno w T[ti] i wywołujemy rekurencyjnie funkcję 'rozklad', aby do wydłużonego rozkładu dopisała wszystkie rozkłady m-i o pierwszym składniku nieprzekraczającym i.
Zwróć uwagę, że tablica T przekazywana jest przez zmienną i dlatego jej zawartość nie jest kopiowana. Tablica T mogłaby też być zmienną  globalną (dla procedury 'Suma'), ponieważ i tak wszystkie wywołania funkcji rozklad korzystają z tej samej tablicy zadeklarowanej w głównej części procedury 'Suma'.
Zauważ, że można by też tak napisać procedurę 'rozklad', aby nigdy nie wywoływała się rekurencyjnie dla m=0. Wypisywanie pełnego rozkładu miałoby miejsce wtedy, gdy min(k,m)=m (czyli k>=m) i oczywiscie petla 'for' zaczynalaby sie w takim przypadku od m-1.
Druga możliwa modyfikacja polega na zrezygnowaniu z parametru k, ponieważ k albo jest równe T[ti], albo m jeśli ti=0. Mozna by też użyć strażnika T[0]=n i zawsze mielibyśmy k=T[ti].
Poza wspomnianymi modyfikacjami całą procedurę 'rozkład' można by napisać w sposób ''rosnący'', tzn. zamiast generować coraz mniejsze składniki - generować coraz większe, aż osiągniemy, bądź przekroczymy n. W takim wypadku składniki należałoby wypisywać w odwrotnej kolejności.
</div>
</div>
<!-- to zadanie tu nie pasuje, wymaga zdecydowanie rekordow z wariantami...
==Zadanie 7 (Parser)==
Dla zadanej poniżej gramatyki języka programowania (będącego uproszczoną wersją Pascala) napisz metodą zejść rekurencyjnych zestaw procedur weryfikujących poprawność programów zapisanych w tym języku. Należy sprawdzić poprawność programu względem podanej gramatyki oraz czy wszystkie zmienne występujące w programie są zadeklarowane i czy wszystkie zadeklarowane zmienne są użyte. Można założyć, że w całym programie nie wystąpi więcej niż Z zmiennych. W przypadku napotkania błędu należy wypisać stosowny komunikat i zakończyć działanie.
Należy założyć istnienie procedury GetSym(Symbol), która daje kolejny symbol (identyfikator, liczbę, operator (:=,<,>,<=,>=,=,<>),  separator (;, ., (, ) ) z wejścia.
Gramatyka:
W opisie gramatyki występują następujące symbole:
{| border="1" cellpadding="5" cellspacing="0"
|-
| <nieterminal> || 
|-
| terminal ||
|-
| { coś }  || wielokrotne (być może 0-krotne) wystąpienie cosia
|-
| &rarr;  || rozdziela lewą część produkcji od prawej
|-
| | |      || rozdziela poszczególne produkcje
|}
Jest to trochę rozszerzona (o nawiasy klamrowe { } ) gramatyka bezkontekstowa.
{| border="0" cellpadding="4" cellspacing="0"
|-
| <program>    || &rarr; || <deklaracja> begin <ciąg instrukcji> end .
|-
| <ciąg instrukcji>  || &rarr; ||  <instrukcja> { ; <instrukcja> }
|-
| <deklaracja>  || &rarr; ||  var <zmienna> { , <zmienna> } ;
|-
| <instrukcja>  || &rarr; ||  while <warunek> do <instrukcja>
|-
|    || || | | if <warunek> then <instrukcja> else <instrukcja>
|-
|    || || | | begin <ciąg instrukcji> end
|-
|    || || | | <zmienna> := <wyrażenie>
|-
| <warunek> || &rarr; || <składnik> {or <składnik>}
|-
| <składnik> || &rarr; || <czynnik> {and <czynnik>}
|-
| <czynnik> || &rarr; || | true | false | not <czynnik> | <wyrażenie> <oprel> <wyrażenie> | ( <warunek> )
|-
| <wyrażenie> || &rarr; || | <zmienna> | <liczba>
|-
| <oprel> || &rarr; || | < | <= | > | >= | <> | =
|-
| <zmienna> || &rarr; || ''ciąg liter''
|-
| <liczba> || &rarr; || ''ciąg cyfr''
|}
<!-- to między || i pierwszą | to są parametry komórki, więc żeby wpisać w komórce kreskę, to trzeba zacząc komórkę od _spacja_kreska_  :) - - >
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1''' 
<div class="mw-collapsible-content" style="display:none">
W tym zadaniu chodzi o przećwiczenie metody zejść rekurencyjnych (była na wykładzie). Niestety na razie nie mamy dostatecznie ciekawych typów danych, żeby móc zapamiętać strukturę danych programu (i np. po tem go wykonywać). Tym nie mniej zadanie jest pouczające. Typ danych który ma być wymyślony to rekord z wariantami. Można uatrakcyjnić to zadanie każąc sprawdzać, czy każda użyta zmienna była wcześniej zadeklarowana i czy nie była deklarowana kilkakrotnie (tablica napisów).
</div>
</div>
-->

Aktualna wersja na dzień 13:18, 28 maj 2020

<<< Powrót do modułu Wprowadzenie do programowania

Ta strona zawiera podstawowe zadania na tablice.

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


Zadanie 1 (Flaga polska)

Tablica A typu array[1..N] of integer (N > 0) wypełniona zerami i jedynkami reprezentuje ciąg N urn w których znajdują się żetony białe (0) i czerwone (1). Podaj algorytm działania automatu przestawiającego żetony w urnach tak, by najpierw były żetony czerwone, potem białe. Robot może wykonywać dwa rodzaje operacji:

  • Kol(i) - podaje kolor żetonu w i-tej urnie (1 ≤ i ≤ n)
  • Z(i,j) - zamienia żetony z i-tej i j-tej urny (1 ≤ i,j ≤ n)

Uwagi:

  1. Operacja Kol jest bardzo kosztowna, więc zależy nam na tym by kolor każdego żetonu był sprawdzany co najwyżej raz.
  2. Robot potrafi zapamiętać tylko kilka wartości z przedziału 0..N+1.
  3. Nie można założyć, że występuje choć jeden żeton w każdym z kolorów.


Wskazówka 1

Rozwiązanie 1


Wskazówka 2

Rozwiązanie 2


Wskazówka 3

Rozwiązanie 3


Wskazówka 4

Rozwiązanie 4


Ćwiczenie 1


Ćwiczenie 2

Zadanie 2 (Flaga trójkolorowa)

Dana jest tablica A typu array[1..N] of integer (N > 0). Należy tak poprzestawiać w niej elementy, żeby najpierw były elementy ujemne, potem równe zero, a na końcu dodatnie.

Wskazówka 1

Rozwiązanie 1

Rozwiązanie 2

Zadanie 3 (Najdłuższe plateau)

Napisz program znajdujący w zadanej tablicy A typu array[1..N] of integer, N > 0, długość najdłuższego stałego segmentu (spójnego fragmentu tablicy).

Wskazówka 1

Rozwiąznie 1


Wskazówka 2

Rozwiąznie 2


Ćwiczenie 1

Inna wersja zadania

A co byłoby gdyby tablica była posortowana ?

Wskazówka 3

Rozwiąznie 3

Zadanie 4 (Segment o maksymalnej sumie)

Napisz program znajdujący w zadanej tablicy A typu array[1..N] of integer, N > 0, maksymalną sumę segmentu (spójnego fragmentu tablicy). Przyjmujemy, że segment pusty ma sumę 0.

Wskazówka 1

Rozwiązanie 1


Wskazówka 2

Rozwiązanie 2


Wskazówka 3

Rozwiązanie 3


Wskazówka 4

Rozwiązanie 4

Rozwiązanie 5

Zadanie 5 (Część wspólna zbiorów)

Dane są dwie tablice A i B typu array[1..N] of integer, N > 0. Obie są posortowane rosnąco. Należy traktując A i B jako reprezentacje dwóch zbiorów wypisać (operacją write) część wspólną tych zbiorów.

Wskazówka 1

Rozwiąznie 1

Zadanie 6 (Suma zbiorów)

Dane są dwie tablice A i B typu array[1..N] of integer, N > 0. Obie są posortowane rosnąco. Należy traktując A i B jako reprezentacje dwu zbiorów wypisać (operacją write) sumę tych zbiorów.

Wskazówka 1

Rozwiązanie 1


Ćwiczenie 1

Wskazówka 2

Rozwiązanie 2

Zadanie 7 (Podciąg)

Dane są dwie tablice A typu array[1..N] of integer i B typu array[1..M] of integer, N, M > 0. Napisz program sprawdzający, czy A jest podciągiem B (tzn. czy istnieje funkcja f, rosnąca, z 1..N w 1..M, t. ze A[i]=B[f(i)]).

Wskazówka 1

Rozwiązanie 1

Zadanie 8 (Odwracanie tablicy)

Dana tablica A typu array[0..N-1] of integer, N > 1. Napisz program odwracający kolejność elementów w A.

Wskazówka 1

Rozwiązanie 1


Wskazówka 2

Rozwiązanie 2

Zadanie 9 (Przesunięcie cykliczne)

Dana tablica A typu array[0..N-1] of integer, N > 1, i liczba naturalna k > 1. Napisz program realizujący przesunięcie cykliczne w prawo o k pól, czyli przesuwający zawartość pola A[i] na A[(i+k) mod N] dla każdego i < N.

Wskazówka 1

Rozwiązanie 1


Wskazówka 2

Rozwiązanie 2


Wskazówka 3

Rozwiązanie 3

Zadanie 10 (Następna permutacja)

Tablica A typu array[1..N] of integer, N > 0, zawiera pewną permutację liczb 1.. N. Napisz program wpisujący do A następną leksykograficznie permutację. Zakładamy, że permutacja w A nie jest ostatnia leksykograficznie.

Przykład Dla N=3 kolejne permutacje w porządku leksykograficznym wyglądają następująco:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

Wskazówka 1

Rozwiąznie 1

Zadanie 11 (Segment o danej sumie)

Tablica A typu array[1..N] of integer, N > 0, zawiera tylko liczby dodatnie. Napisz program, który dla danego W typu integer sprawdza, czy w A istnieje segment o sumie W (czyli czy istnieją l, p takie, że W=A[l]+...+A[p1]).

Wskazówka 1

Rozwiązanie 1


Wskazówka 2

Rozwiązanie 2

Zadanie 12 (Głosowanie większościowe)

Dana jest tablica A typu array[1..N] of integer, N > 0. Sprawdź, czy jest w niej element wystepujący więcej niż N/2 razy i jeśli tak - wskaż go.

Wskazówka 1

Rozwiąznie 1


Wskazówka 2

Rozwiązanie 2

Zadanie 13 (Arytmetyka liczb wielocyfrowych)

Liczby wielocyfrowe będą reprezentowane w tablicach typu liczba=array[0..N-1] of integer, N > 1, w taki sposób, że najmniej znacząca cyfra jest pod indeksem 0. Rozpatrujemy liczby przy podstawie b > 1. Napisz procedury obliczające:

  1. sumę liczb A i B do C. Jeśli wynik nie zmieści się w C, to wartość C nie ma znaczenia. Zmienna przepełnienie wskazuje czy do niego doszło czy nie.
  2. różnicę A i B do C. Jeśli wynik miałby byc liczbą ujemną, to wartość C nie ma znaczenia. Zmienna ujemny wskazuje jaki jest znak wyniku.
  3. iloczyn A i B do C (C powinno być tablicą dwa razy dłuższą niż A i B, żeby móc pomieścić wynik).

Rozwiązanie 1