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

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
 
(Nie pokazano 67 wersji utworzonych przez 7 użytkowników)
Linia 1: Linia 1:
{{powrot|Wstęp do programowania| do głównej strony wykładu}}
{{powrot|WDP_Wprowadzenie_do_programowania|do modułu Wprowadzenie do programowania}}
{{powrot|WDP_Wprowadzenie_do_programowania|do modułu Wprowadzenie do programowania}}


Ta strona zawiera podstawowe zadania na tablice oraz rekurencję.
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 23: Linia 21:




{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
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>
<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">
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>
}}


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' FlagaPolska1(N:integer; A:array[1..N] of integer);
  '''program''' FlagaPolska1(N:integer; A:array[1..N] of integer);
  //Tablica A jest wypełniona zerami i jedynkami  
  //Tablica A jest wypełniona zerami i jedynkami  
Linia 47: Linia 48:
''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
</div>
</div>
</div>}}
</div>
 


{{wskazowka| 2||
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span>
<div class="mw-collapsible-content" style="display:none">
<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.</div>
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>
}}


{{rozwiazanie| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 2</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' FlagaPolska2(N:integer; A:array[1..N] of integer);
  '''program''' FlagaPolska2(N:integer; A:array[1..N] of integer);
  //Tablica A jest wypełniona zerami i jedynkami  
  //Tablica A jest wypełniona zerami i jedynkami  
Linia 75: 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 81: Linia 83:
''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
</div>
</div>
</div>}}
</div>
 


{{wskazowka| 3||
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 3</span>
<div class="mw-collapsible-content" style="display:none">
<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. </div>
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>
}}


{{rozwiazanie| 3||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 3</span>
<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);
  //Tablica A jest wypełniona zerami i jedynkami  
  //Tablica A jest wypełniona zerami i jedynkami  
Linia 99: 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 120: 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 126: Linia 129:
''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
</div>
</div>
</div>}}
</div>
 


{{wskazowka| 4||
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 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. </div>
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>
}}


{{rozwiazanie| 4||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 4</span>
<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);
  //Tablica A jest wypełniona zerami i jedynkami  
  //Tablica A jest wypełniona zerami i jedynkami  
Linia 156: Linia 160:
''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
</div>
</div>
</div>}}
</div>




{{cwiczenie| 1|pytanko 1|<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Ćwiczenie 1</span>
<div class="mw-collapsible-content" style="display:none">
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>


{{cwiczenie| 2|pytanko 2|<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<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">
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) ==
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.
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.


{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
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.
<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">
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>}}


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' FlagaTrójkolorowa(N:integer; A:array[1..N] of integer);
  '''program''' FlagaTrójkolorowa(N:integer; A:array[1..N] of integer);
  '''var''' m,r,w,pom : integer;
  '''var''' m,r,w,pom : integer;
Linia 199: Linia 212:
''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały


[http://www.mimuw.edu.pl/~annan/modul2_2_1.html Wizualizacja]
[[pimp:modul2_2_1.html|Wizualizacja]]


</div>
</div>
</div>}}
</div>


{{rozwiazanie| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 2</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' FlagaTrójkolorowa(N:integer; A:array[1..N] of integer);
  '''program''' FlagaTrójkolorowa(N:integer; A:array[1..N] of integer);
  '''var''' m,r,w,pom : integer;
  '''var''' m,r,w,pom : integer;
Linia 217: 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 228: Linia 249:
''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały


[[pimp:modul2_2_2.html|Wizualizacja]]
</div>
</div>
</div>
</div>}}


== 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).


{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
<div class="mw-collapsible-content" style="display:none">
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>


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<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">
  '''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;
Linia 258: Linia 285:


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


{{wskazowka| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span>
<div class="mw-collapsible-content" style="display:none">
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>


{{rozwiazanie| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<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">
  '''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;
   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>}}


{{cwiczenie| 1|pytanko 1|<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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 ?
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Ćwiczenie 1</span>
<div class="mw-collapsible-content" style="display:none">
Czy 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 ?


{{wskazowka| 3||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
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].   
<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">
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>}}


{{rozwiazanie| 3||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<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">
  '''program''' NajdłuższePlateau3(N:integer; A:array[1..N] of integer);
  '''program''' NajdłuższePlateau3(N:integer; A:array[1..N] of integer);
  '''var''' i,maks: integer;
  '''var''' i,maks: integer;
Linia 311: Linia 357:


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


== 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.


{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
<div class="mw-collapsible-content" style="display:none">
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>


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' SegmentOMaksymalnejSumie1(N:integer; A:array[1..N] of integer);
  '''program''' SegmentOMaksymalnejSumie1(N:integer; A:array[1..N] of integer);
  '''var''' l,p,j,suma,maks: integer;
  '''var''' l,p,j,suma,maks: integer;
Linia 338: Linia 391:


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


{{wskazowka| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span>
<div class="mw-collapsible-content" style="display:none">
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">
{{rozwiazanie| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<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">
  '''program''' SegmentOMaksymalnejSumie2(N:integer; A:array[1..N] of integer);
  '''program''' SegmentOMaksymalnejSumie2(N:integer; A:array[1..N] of integer);
  '''var''' l,p,suma, maks: integer;
  '''var''' l,p,suma, maks: integer;
Linia 362: Linia 422:


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


{{wskazowka| 3||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 3</span>
<div class="mw-collapsible-content" style="display:none">
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">
{{rozwiazanie| 3||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<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">
  '''program'''  SegmentOMaksymalnejSumie3(N:integer; A:array[1..N] of integer);
  '''program'''  SegmentOMaksymalnejSumie3(N:integer; A:array[1..N] of integer);
  '''var''' mini_pref,biez_pref,maks,i: integer;
  '''var''' mini_pref,biez_pref,maks,i: integer;
Linia 386: Linia 453:


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


{{wskazowka| 4||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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 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 mw-made=collapsible mw-collapsed">
<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">
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>}}


{{rozwiazanie| 4||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 4</span>
<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,suma: 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'''
     '''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>}}


{{rozwiazanie| 5||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 5</span>
<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).  
  '''program'''  SegmentOMaksymalnejSumie5(N:integer; A:array[1..N] of integer);
  '''program'''  SegmentOMaksymalnejSumie5(N:integer; A:array[1..N] of integer);
Linia 439: Linia 520:


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


== 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">
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<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">
  '''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);
  //Tablice A i B są posortowane rosnąco
  //Tablice A i B są posortowane rosnąco
Linia 471: Linia 558:


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


== Zadanie 6 (Suma zbiorów) ==
== Zadanie 6 (Suma zbiorów) ==
Linia 479: Linia 569:
zbiorów wypisać (operacją write) sumę tych zbiorów.
zbiorów wypisać (operacją write) sumę tych zbiorów.


{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
Dopóki istnieją elementy w obu tablicach przesuwamy się tak jak przy obliczaniu części wspólnej, potem obługujemy końcówki tablic.
<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">
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>}}


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' Suma(N:integer; A,B:array[1..N] of integer);
  '''program''' Suma(N:integer; A,B:array[1..N] of integer);
  //Tablice A i B są posortowane rosnąco
  //Tablice A i B są posortowane rosnąco
Linia 505: Linia 599:
         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>}}


{{cwiczenie| 1|pytanko 1|<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Ćwiczenie 1</span>
<div class="mw-collapsible-content" style="display:none">
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>


{{wskazowka| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
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.
<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">
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>}}


{{rozwiazanie| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 2</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' Suma(N:integer; A,B:array[1..N] of integer);
  '''program''' Suma(N:integer; A,B:array[1..N] of integer);
  //Tablice A i B są posortowane rosnąco
  //Tablice A i B są posortowane rosnąco
Linia 557: Linia 661:


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


== 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)]).


{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
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.   
<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">
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>}}


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
  '''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);
  '''var''' ia,ib: integer;
  '''var''' ia,ib: integer;
Linia 589: Linia 700:


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


== 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.


{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
Należy zamienić element 0 z N-1, 2 z N-2 itd.
<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">
Należy zamienić element 0 z N-1, 1 z N-2 itd.
</div>
</div>
</div>
</div>}}


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' Odwracanie1(N:integer; A:array[0..N-1] of integer);
  '''program''' Odwracanie1(N:integer; A:array[0..N-1] of integer);
  '''var''' l,pom: integer;
  '''var''' l,pom: integer;
Linia 615: Linia 733:


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


{{wskazowka| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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 class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span>
<div class="mw-collapsible-content" style="display:none">
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>}}


{{rozwiazanie| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 2</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' Odwracanie2(N:integer; A:array[0..N-1] of integer);
  '''program''' Odwracanie2(N:integer; A:array[0..N-1] of integer);
  '''var''' l,p,pom: integer;
  '''var''' l,p,pom: integer;
Linia 639: 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 653: Linia 781:
  '''end'''.  
  '''end'''.  
</div>
</div>
</div>}}
</div>


== 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.


{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
<div class="mw-collapsible-content" style="display:none">
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.
</div>
</div>
</div>}}
</div>
{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' Przesuń1(N,k:integer; A:array[0..N-1] of integer);
  '''program''' Przesuń1(N,k:integer; A:array[0..N-1] of integer);
  '''var''' i: integer;
  '''var''' i: integer;
Linia 673: Linia 805:


''Koszt pamięciowy'': liniowy względem N
''Koszt pamięciowy'': liniowy względem N
[[pimp:modul2_9_1.html|Wizualizacja]]
</div>
</div>
</div>
</div>}}


{{wskazowka| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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.  
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span>
<div class="mw-collapsible-content" style="display:none">
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>}}


{{rozwiazanie| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
  '''program''' Przesuń2(N,k:integer; A:array[1..N] of integer);
<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">
  '''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 694: 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 703: Linia 843:
''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
</div>
</div>
</div>}}
</div>


{{wskazowka| 3||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 3</span>
<div class="mw-collapsible-content" style="display:none">
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>


{{rozwiazanie| 3||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
  '''program''' Przesun3(N,k:integer; A:array[1..N] of integer);
<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">
  '''program''' Przesun3(N,k:integer; A:array[0..N-1] of integer);
  // k > 1
  // k > 1
  '''begin'''
  '''begin'''
Linia 718: 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 727: 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 741: Linia 889:
  3 2 1
  3 2 1


{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
Zastanów się która część talicy pozostanie taka sama w następnej permutacji.
<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">
Zastanów się, która część tablicy pozostanie taka sama w następnej permutacji.
</div>
</div>
</div>
</div>}}


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<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">
  '''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
  '''var''' i,k,pom: integer;
  '''var''' i,k,pom: integer;
    wyjdz: boolean;
  '''begin'''
  '''begin'''
   i:=N-1;
   i:=N-1;
  wyjdz:=false;
   '''while''' A[i] > A[i+1] '''do''' i:=i-1;
   '''while''' i >= 1 and not wyjdz '''do'''
   k:=N;
      '''if''' A[i] > A[i+1] '''then''' i:=i-1
  '''while''' A[k] < A[i] '''do''' k:=k-1;
      '''else''' wyjdz:=true;
  pom:=A[i];
   '''if''' i >= 1 '''then''' '''begin'''
  A[i]:=A[k];
    k:=N;
  A[k]:=pom;
    wyjdz:=false;
  OdwracanieTablicy(A,i+1,N);
    '''while''' k >= i and not wyjdz '''do'''
      '''if''' A[k] < A[i] '''then''' k:=k-1
      '''else''' wyjdz:=true;
    pom:=A[i];
    A[i]:=A[k];
    A[k]:=pom;
    OdwracanieTablicy(A,i+1,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>).


{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 1</span>
<div class="mw-collapsible-content" style="display:none">
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>}}


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
  '''program''' SegmentODanejSumie1(N,W:integer; A:array[1..N] of integer);
  '''program''' SegmentODanejSumie1(N,W:integer; A:array[1..N] of integer);
  //Tablica A zawiera tylko liczby dodatnie
  //Tablica A zawiera tylko liczby dodatnie
Linia 814: Linia 965:


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


{{wskazowka| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span>
<div class="mw-collapsible-content" style="display:none">
Podobnie jak w zadaniu o segmencie o maksymalnej sumie, możliwe też jest rozwiązanie o liniowym koszcie czasowym.
</div>
</div>
</div>
</div>}}


{{rozwiazanie| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 2</span>
<div class="mw-collapsible-content" style="display:none">
  '''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 833: 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);
Linia 849: Linia 1008:
   '''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">
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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">
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>


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<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">
  '''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 884: Linia 1055:


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


{{wskazowka| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
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ł.
<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">
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>}}


{{rozwiazanie| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
  '''program''' Głosowanie2(N,W:integer; A:array[1..N] of integer);
<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">
  '''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 907: Linia 1086:
       '''end''';
       '''end''';
   '''end''';
   '''end''';
   ile:=0; //sprawdzamy czy kandydat jest liderem
   ile:=0; //sprawdzamy, czy kandydat jest liderem
   '''for''' i:=1 '''to''' N '''do'''  
   '''for''' i:=1 '''to''' N '''do'''  
     '''if''' A[i]=kand '''then''' ile:=ile+1;  
     '''if''' A[i]=kand '''then''' ile:=ile+1;  
Linia 920: Linia 1099:


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


== 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).  


{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie 1</span>
<div class="mw-collapsible-content" style="display:none">
  '''const''' N=100;  
  '''const''' N=100;  
   b=10;  
   b=10;  
Linia 937: 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 955: 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 980: 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 993: Linia 1177:
''Koszt pamięciowy'': stały
''Koszt pamięciowy'': stały
</div>
</div>
</div>}}
==Zadanie 14 (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.)
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>}}
{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>}}
{{cwiczenie| 1|pytanko 1|<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
Ile razy maksymalnie może być wywołana funkcja 'szukaj' dla tego samego punktu?
</div>
</div>}}
{{cwiczenie| 2|pytanko 2|<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>}}
{{cwiczenie| 3|pytanko 3|<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>}}
{{odpowiedz||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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 15 (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.
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>}}
{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>}}
{{rozwiazanie| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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 16 (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.
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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;
-->
{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>}}
{{cwiczenie| 1|pytanko 1|<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
Jaki przypadek jest najgorszy i ile trzeba wykonać wtedy ruchów?
</div>
</div>}}
{{odpowiedz||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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 17 (Ustawianie hetmanów)==
Napisz procedurę znajdująca wszystkie takie rozstawienia 8 hetmanów na szachownicy, by żadne dwa hetmany się nie atakowały.
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>}}
{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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 18 (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.
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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 19 (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
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>}}
{{wskazowka| 2||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>}}
{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
'''procedure''' Suma(n:integer);
// 1 <= n
  '''var''' T:'''array'''[1..n] '''of''' integer;
  '''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'''
      write(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
'''begin'''   
  rozklad(T,0,n,n);
'''end'''
''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_  :) - - >
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><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>
</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