Wstęp do programowania/Wstęp do algorytmów/Ćwiczenia: Różnice pomiędzy wersjami
m (→Zadanie 4) |
|||
(Nie pokazano 12 pośrednich wersji utworzonych przez tego samego użytkownika) | |||
Linia 10: | Linia 10: | ||
Podaj algorytm wyliczający część wspólną dwóch zadanych prostokątów o bokach równoległych do osi układu współrzędnych. | Podaj algorytm wyliczający część wspólną dwóch zadanych prostokątów o bokach równoległych do osi układu współrzędnych. | ||
===Analiza specyfikacji=== | ===Analiza specyfikacji=== | ||
* Czy specyfikacja podana w zadaniu jest wystarczająca do zapisania algorytmu? | *Czy specyfikacja podana w zadaniu jest wystarczająca do zapisania algorytmu? | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Odpowiedź</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
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. | 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. | ||
</div> | </div> | ||
</div> | </div> | ||
*Co może być częścią wspólną ? | *Co może być częścią wspólną ? | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Odpowiedź</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
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. | 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> | ||
*Jaka może być postać danych ? | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Odpowiedź</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Można rozważać kilka różnych postaci: | Można rozważać kilka różnych postaci: | ||
# współrzędne dwu przeciwległych wierzchołków, | # współrzędne dwu przeciwległych wierzchołków, | ||
Linia 40: | Linia 47: | ||
Reprezentacje 3,4,5 są poprawne. W zależności od tego co chcemy robić z wynikiem naszych obliczeń, mogą się okazać warte wybrania. | Reprezentacje 3,4,5 są poprawne. W zależności od tego co chcemy robić z wynikiem naszych obliczeń, mogą się okazać warte wybrania. | ||
Reprezentacje 2 i 1 wydają się równoważne, dopiero przy wyborze reprezentacji wyniku okaże się, że różnica między nimi w tym akurat zadaniu jest bardzo istotna.</div> | Reprezentacje 2 i 1 wydają się równoważne, dopiero przy wyborze reprezentacji wyniku okaże się, że różnica między nimi w tym akurat zadaniu jest bardzo istotna.</div> | ||
</div> | </div> | ||
*Jaka może być postać wyniku? | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Odpowiedź</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Skoro możemy traktować każdy możliwy wynik jako (być może zdegenerowany) prostokąt o bokach równoległych do osi układu, to byłoby dobrze użyć tu tej samej reprezentacji, co dla danych (nam jako piszącym będzie łatwiej, a przede wszystkim jest to lepsze dla użytkownika, który będzie mógł zastosować nasz algorytm do wyników przez ten algorytm policzonych). I tu ujawnia się wyższość reprezentacji 2, która pozwala reprezentować także pusty prostokąt, w przeciwieństwie do reprezentacji 1. (Reprezentacje 3-6 też są dobre, moglibyśmy także np. rysować wynik na ekranie.) | Skoro możemy traktować każdy możliwy wynik jako (być może zdegenerowany) prostokąt o bokach równoległych do osi układu, to byłoby dobrze użyć tu tej samej reprezentacji, co dla danych (nam jako piszącym będzie łatwiej, a przede wszystkim jest to lepsze dla użytkownika, który będzie mógł zastosować nasz algorytm do wyników przez ten algorytm policzonych). I tu ujawnia się wyższość reprezentacji 2, która pozwala reprezentować także pusty prostokąt, w przeciwieństwie do reprezentacji 1. (Reprezentacje 3-6 też są dobre, moglibyśmy także np. rysować wynik na ekranie.) | ||
</div> | </div> | ||
</div> | </div> | ||
=== Znajdowanie algorytmu === | === Znajdowanie algorytmu === | ||
Linia 52: | Linia 62: | ||
[[Grafika:Prostokaty.png]] | [[Grafika:Prostokaty.png]] | ||
<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"> | |||
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. | 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> | </div> | ||
<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"> | |||
Dane są dwa odcinki na prostej. Zastanów się, jaka może być wartość lewego końca części wspólnej tych odcinków. | 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> | </div> | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Załóżmy, że mamy operacje min i max. Przyjmijmy oznaczenia: | Załóżmy, że mamy operacje min i max. Przyjmijmy oznaczenia: | ||
A, B, W - prostokąty dane i wynikowy (odpowiednio) | A, B, W - prostokąty dane i wynikowy (odpowiednio) | ||
Linia 74: | Linia 90: | ||
(współrzędne y-owe rosną w górę, tak jak w matematyce, a nie w dól jak na ekranie komputera). | (współrzędne y-owe rosną w górę, tak jak w matematyce, a nie w dól jak na ekranie komputera). | ||
</div> | </div> | ||
</div> | </div> | ||
=== Testowanie === | === Testowanie === | ||
Linia 83: | Linia 99: | ||
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)! | 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)! | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Dowód</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Najpierw zauważmy, że | Najpierw zauważmy, że | ||
p ε A ∩ B wtedy i tylko wtedy p.x ε rzutX(A) ∩ rzutX(B) i p.y ε rzutY(A) ∩ rzutY(B) | p ε A ∩ B wtedy i tylko wtedy p.x ε rzutX(A) ∩ rzutX(B) i p.y ε rzutY(A) ∩ rzutY(B) | ||
Linia 102: | Linia 120: | ||
W drugą stronę dowód przebiega podobnie. Ponieważ p.x ε rzutX(W) to max(A.x1,B.x1) ≤ p.x ≤ min(A.x2,B.x2). Stąd A.x1 ≤ p.x ≤ A.x2 a więc p.x ε rzutX(A). I tak samo dla B. A więc p.x ε rzutX(A) ∩ rzutX(B). | W drugą stronę dowód przebiega podobnie. Ponieważ p.x ε rzutX(W) to max(A.x1,B.x1) ≤ p.x ≤ min(A.x2,B.x2). Stąd A.x1 ≤ p.x ≤ A.x2 a więc p.x ε rzutX(A). I tak samo dla B. A więc p.x ε rzutX(A) ∩ 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. | ||
Linia 114: | Linia 132: | ||
Podaj algorytm wyliczający najmniejszy prostokąt o bokach równoległych do osi układu współrzędnych, zawierający dwa zadane prostokąty o bokach równoległych do osi układu współrzędnych. | Podaj algorytm wyliczający najmniejszy prostokąt o bokach równoległych do osi układu współrzędnych, zawierający dwa zadane prostokąty o bokach równoległych do osi układu współrzędnych. | ||
<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</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Jeśli zinterpretujemy niejasności w specyfikacji, tak jak to zrobiliśmy w Zadaniu 1, to okaże się, że jest to zadanie „dualne” do Zadania 1. | Jeśli zinterpretujemy niejasności w specyfikacji, tak jak to zrobiliśmy w Zadaniu 1, to okaże się, że jest to zadanie „dualne” do Zadania 1. | ||
</div> | </div> | ||
</div> | </div> | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Przyjmijmy oznaczenia: | Przyjmijmy oznaczenia: | ||
A, B, W - prostokąty dane i wynikowy (odpowiednio) | A, B, W - prostokąty dane i wynikowy (odpowiednio) | ||
Linia 133: | Linia 155: | ||
Dowód poprawności jest analogiczny do tego z Zadania 1. | Dowód poprawności jest analogiczny do tego z Zadania 1. | ||
</div> | </div> | ||
</div> | </div> | ||
== Zadanie 3== | == Zadanie 3== | ||
Używając tylko czterech podstawowych działań arytmetycznych, sprawdź, czy dwa odcinki na płaszczyźnie zadane porzez współrzędne końców przecinają się. | Używając tylko czterech podstawowych działań arytmetycznych, sprawdź, czy dwa odcinki na płaszczyźnie zadane porzez współrzędne końców przecinają się. | ||
<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"> | |||
Tym razem nie wystarczy sprawdzić rzutów na oś X i Y. | Tym razem nie wystarczy sprawdzić rzutów na oś X i Y. | ||
</div> | </div> | ||
</div> | </div> | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 2</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Oznaczmy końce odcinków jako p,q oraz r,s. Dwa odcinki pq i rs się | Oznaczmy końce odcinków jako p,q oraz r,s. Dwa odcinki pq i rs się | ||
przecinają wtedy i tylko wtedy, gdy punkty p i q leżą po przeciwnych stronach prostej rs, zaś punkty r i s po przeciwnych stronach prostej pq lub któryś z końców jednego z odcinków należy do drugiego | przecinają wtedy i tylko wtedy, gdy punkty p i q leżą po przeciwnych stronach prostej rs, zaś punkty r i s po przeciwnych stronach prostej pq lub któryś z końców jednego z odcinków należy do drugiego | ||
odcinka. | odcinka. | ||
</div> | </div> | ||
</div> | </div> | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka 3</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Najpierw rozwiążmy kilka zadań pomocniczych: | Najpierw rozwiążmy kilka zadań pomocniczych: | ||
Linia 189: | Linia 217: | ||
'''wpp''' ROZŁĄCZNE | '''wpp''' ROZŁĄCZNE | ||
</div> | </div> | ||
</div> | </div> | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Chcemy sprawdzić, czy odcinki pq i rs się przecinają. Przyjmijmy oznaczenia: | Chcemy sprawdzić, czy odcinki pq i rs się przecinają. Przyjmijmy oznaczenia: | ||
Mp=M(r,s,p) | Mp=M(r,s,p) | ||
Linia 207: | Linia 237: | ||
Sprawdź_czy_wpółliniowe_się_przecinają(pq, rs) | Sprawdź_czy_wpółliniowe_się_przecinają(pq, rs) | ||
</div> | </div> | ||
</div> | </div> | ||
== Zadanie 4== | == Zadanie 4== | ||
Sprawdź, czy dane dwa równoległoboki na płaszczyźnie przecinają się. Równoległoboki mają boki dowolnie nachylone do osi współrzędnych i zadane są poprzez współrzędne czterech rogów podanych zgodnie z ruchem wskazówek zegara. | Sprawdź, czy dane dwa równoległoboki na płaszczyźnie przecinają się. Równoległoboki mają boki dowolnie nachylone do osi współrzędnych i zadane są poprzez współrzędne czterech rogów podanych zgodnie z ruchem wskazówek zegara. | ||
<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</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
I tym razem nie wystarczy sprawdzić rzutów na oś X i Y. Trzeba użyć zadania o przecinaniu się odcinków. | I tym razem nie wystarczy sprawdzić rzutów na oś X i Y. Trzeba użyć zadania o przecinaniu się odcinków. | ||
</div> | </div> | ||
</div> | </div> | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span> | |||
<div class="mw-collapsible-content" style="display:none"> | |||
Niech R=(r_1,r_2,r_3,r_4) i Q=(q_1,q_2,q_3,q_4) to dane równoległoboki. Żeby R i Q się przecinały, to albo ich boki muszą się przecinać, albo jeden równoległobok musi być zawarty w drugim. | Niech R=(r_1,r_2,r_3,r_4) i Q=(q_1,q_2,q_3,q_4) to dane równoległoboki. Żeby R i Q się przecinały, to albo ich boki muszą się przecinać, albo jeden równoległobok musi być zawarty w drugim. | ||
Linia 235: | Linia 268: | ||
'''jeśli''' (M12*M43 < 0 i M14*M23 <0) lub (N12*N43 < 0 i N14*N23 <0) '''to''' wynik=PRZECINAJĄ SIĘ | '''jeśli''' (M12*M43 < 0 i M14*M23 <0) lub (N12*N43 < 0 i N14*N23 <0) '''to''' wynik=PRZECINAJĄ SIĘ | ||
</div> | </div> | ||
</div> | </div> |
Aktualna wersja na dzień 14:22, 26 maj 2020
To są zadania na prostokąty i odcinki.
Oglądaj wskazówki i rozwiązania __SHOWALL__
Ukryj wskazówki i rozwiązania __HIDEALL__
Zadanie 1
Podaj algorytm wyliczający część wspólną dwóch 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.
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 testowanie nie wykryje błędów, nic ono 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 (<, >).
Zadanie 2
Podaj algorytm wyliczający najmniejszy prostokąt o bokach równoległych do osi układu współrzędnych, zawierający dwa zadane prostokąty o bokach równoległych do osi układu współrzędnych.
Wskazówka
Rozwiązanie
Zadanie 3
Używając tylko czterech podstawowych działań arytmetycznych, sprawdź, czy dwa odcinki na płaszczyźnie zadane porzez współrzędne końców przecinają się.
Wskazówka 1
Wskazówka 2
Wskazówka 3
Rozwiązanie
Zadanie 4
Sprawdź, czy dane dwa równoległoboki na płaszczyźnie przecinają się. Równoległoboki mają boki dowolnie nachylone do osi współrzędnych i zadane są poprzez współrzędne czterech rogów podanych zgodnie z ruchem wskazówek zegara.
Wskazówka
Rozwiązanie