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

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Daria (dyskusja | edycje)
Zadanie o prostokątach
Daria (dyskusja | edycje)
Zmiany do zadania o prostokatach
Linia 6: Linia 6:
'''Odpowiedź'''   
'''Odpowiedź'''   
<div class="mw-collapsible-content" style="display:none">  
<div class="mw-collapsible-content" style="display:none">  
Nie, nie wiadomo co to znaczy zadane, nie wiadomo co zlecający wykonanie
Nie, nie wiadomo co to znaczy zadane, nie wiadomo czy prostokąty są domknięte (z brzegiem), nie wiadomo co zlecający wykonanie zadania rozumiał przez wyliczanie.
zadania rozumiał przez wyliczanie.
</div>
</div>
</div>
</div>
Linia 14: Linia 13:
'''Odpowiedź'''   
'''Odpowiedź'''   
<div class="mw-collapsible-content" style="display:none">  
<div class="mw-collapsible-content" style="display:none">  
Prostokąt o bokach równoległych do osi układu, odcinek pionowy lub poziomy, punkt, zbiór pusty; wszystkie te przypadki możemy traktować jako szczególne rodzaje pierwszego przypadku.
Jeśli prostokąty są z brzegiem to prostokąt o bokach równoległych do osi układu, odcinek pionowy lub poziomy, punkt, zbiór pusty; wszystkie te przypadki możemy traktować jako szczególne rodzaje pierwszego przypadku.
</div>
</div>
</div>
</div>
Linia 47: Linia 46:
=== Znajdowanie algorytmu ===
=== Znajdowanie algorytmu ===
Gdy zaczniemy analizować możliwe wzajemne położenia prostokątów okaże się, że przypadków jest co najmniej kilkanaście.
Gdy zaczniemy analizować możliwe wzajemne położenia prostokątów okaże się, że przypadków jest co najmniej kilkanaście.
Zamiast tego spróbujmy się zastanowić jaka może być współrzędna x-owa lewego-górnego rogu wynikowego prostokąta.
[[rysunek]]
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1''' 
<div class="mw-collapsible-content" style="display:none">
Zauważ, że wynikowy prostokąt jest iloczynem kartezjańskim dwóch odcinków. Tego, który jest częścią wspólną rzutów obu prostokątów na oś X i tego,  który jest częścią wspólną rzutów obu prostokątów na oś Y. W ten sposób zadanie dwuwymiarowe zostaje zredukowane do dwóch zadań jednowymiarowych.
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 2''' 
<div class="mw-collapsible-content" style="display:none">
Dane są dwa odcinki na prostej. Zastanów się jaka może być wartość lewego końca części wspólnej tych odcinków.
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie'''   
'''Rozwiązanie'''   
Linia 73: Linia 84:
'''Dowód'''   
'''Dowód'''   
<div class="mw-collapsible-content" style="display:none">  
<div class="mw-collapsible-content" style="display:none">  
Najpierw pokażemy, że jeśli p &epsilon; A &cap; B to p &epsilon; W. Ponieważ p &epsilon; A to
Najpierw zauważmy, że  
  A.x1 &le; p.x &le; A.x2
  p &epsilon; A &cap; B   wtedy i tylko wtedy    p.x &epsilon; rzutX(A) &cap; rzutX(B) i p.y &epsilon; rzutY(A) &cap; rzutY(B)
  A.y1 &ge; p.y &ge; A.y2
    p &epsilon; W   wtedy i tylko wtedy              p.x &epsilon; rzutX(W) i p.y &epsilon; rzutY(W)
Podobnie dla B, czyli B.x1 &le; p.x &le; B.x2  i B.y1 &ge; p.y &ge; B.y2. A więc
A więc wystarczy, że niezależnie pokażemy:
  p.x &epsilon; rzutX(A) &cap; rzutX(B)  wtedy i tylko wtedy p.x &epsilon; rzutX(W) i
  p.y &epsilon; rzutY(A) &cap; rzutY(B)  wtedy i tylko wtedy p.y &epsilon; rzutY(W)
co tak naprawdę sprowadza się do zrobienia dowodu w przypadku jednowymiarowym.
 
Załóżmy więc że p.x &epsilon; rzutX(A) &cap; rzutX(B).  Ponieważ p.x &epsilon; rzutX(A) to
A.x1 &le; p.x &le; A.x2.
Podobnie dla B, czyli
  B.x1 &le; p.x &le; B.x2.  
A więc  
  max(A.x1,B.x1) &le; p.x &le; min(A.x2,B.x2)  
  max(A.x1,B.x1) &le; p.x &le; min(A.x2,B.x2)  
min(A.y1,B.y1) &ge; p.y &ge; max(A.y2,B.y2).
Stąd  W.x1 &le; p.x &le; W.x2, czyli p.x &epsilon; rzutX(W).
Stąd  W.x1 &le; p.x &le; W.x2  i  W.y1  &ge; p.y &ge; W.y2, czyli p &epsilon; W.


W drugą stronę dowód przebiega podobnie. Ponieważ  p &epsilon; W to max(A.x1,B.x1)  &le; p.x &le; min(A.x2,B.x2)  i  min(A.y1,B.y1) &ge; p.y &ge; max(A.y2,B.y2). Stąd A.x1 &le; p.x &le; A.x2  i  A.y1 &ge; p.y &ge; A.y2, a więc p &epsilon; A. I tak samo dla B. A więc p &epsilon; A &cap; B.
W drugą stronę dowód przebiega podobnie. Ponieważ  p.x &epsilon; rzutX(W) to max(A.x1,B.x1)  &le; p.x &le; min(A.x2,B.x2). Stąd A.x1 &le; p.x &le; A.x2  a więc p.x &epsilon; rzutX(A). I tak samo dla B. A więc p.x &epsilon; rzutX(A) &cap; rzutX(B).  
</div>
</div>
</div>
</div>
Najważniejszy morał z tego zadania, to pochwała myślenia - trzeba wykonać dużo pracy (myślowej) zanim zacznie się pisać pierwszy wiersz programu/algorytmu.
Najważniejszy morał z tego zadania, to pochwała myślenia - trzeba wykonać dużo pracy (myślowej) zanim zacznie się pisać pierwszy wiersz programu/algorytmu.
===Inna wersja zadania===
A co by było gdyby prostokąty były otwarte (czyli bez brzegu) ?
Reprezentacja używana powyżej jest nadal dobra zarówno dla danych jak i dla wyniku. Tym razem możliwe są tylko dwie postacie wyniku: albo prostokąt (z wnętrzem) o bokach równoległych do osi układu, albo zbiór pusty. Algorytm który podaliśmy powyżej działa również dla prostokątów otwartych; w dowodzie poprawności trzeba by jedynie zamienić nierówności nieostre (&le;, &ge;) na ostre (<, >).

Wersja z 14:00, 18 lip 2006

Zadanie 1

Podaj algorytm wyliczający część wspólną dwu zadanych prostokątów o bokach równoległych do osi układu współrzędnych.

Analiza specyfikacji

  • Czy specyfikacja podana w zadaniu jest wystarczająca do zapisania algorytmu ?

Odpowiedź

  • Co może być częścią wspólną ?

Odpowiedź

  • Jaka może być postać danych ?

Odpowiedź

  • Jaka może być postać wyniku ?

Odpowiedź

Znajdowanie algorytmu

Gdy zaczniemy analizować możliwe wzajemne położenia prostokątów okaże się, że przypadków jest co najmniej kilkanaście. rysunek

Wskazówka 1

Wskazówka 2

Rozwiązanie

Testowanie

Mając algorytm/program powinniśmy go przetestować, czyli sprawdzić jakie daje wyniki dla przykładowych danych. Warto testować z jednej strony przypadki typowe, z drugiej zaś szczególne przypadki graniczne (np. prostokąty dotykające się jednym rogiem lub jeden prostokąt zawarty w drugim). Testowanie jest ważne i trzeba je robić, mimo że, w przypadku gdy nie wykryje błędów, nic nie daje (nawet nie mamy pewności, że dla przetestowanych danych zawsze dostaniemy poprawny wynik, bo np. mamy niezainicjalizowane zmienne).

Dowód poprawności

Skoro testowanie nie daje pewności, że mamy dobry program to potrzebujemy innego narzędzia, które pozwoli nam spać spokojnie - możemy (przynajmniej teoretycznie) dowieść formalnie poprawność programu. Powinniśmy ustalić co jest formalną specyfikacją naszego zadania (W = A ∩ B) i zrobić formalny dowód, że dla każdego punktu p zdanie p ε A ∩ B jest równoważne temu, że p ε W. Teraz już możemy spać spokojnie - nasz algorytm jest poprawny (o ile nie pomylilismy się w dowodzie)!

Dowód

Najważniejszy morał z tego zadania, to pochwała myślenia - trzeba wykonać dużo pracy (myślowej) zanim zacznie się pisać pierwszy wiersz programu/algorytmu.

Inna wersja zadania

A co by było gdyby prostokąty były otwarte (czyli bez brzegu) ?

Reprezentacja używana powyżej jest nadal dobra zarówno dla danych jak i dla wyniku. Tym razem możliwe są tylko dwie postacie wyniku: albo prostokąt (z wnętrzem) o bokach równoległych do osi układu, albo zbiór pusty. Algorytm który podaliśmy powyżej działa również dla prostokątów otwartych; w dowodzie poprawności trzeba by jedynie zamienić nierówności nieostre (≤, ≥) na ostre (<, >).