Metody programowania / Ćwiczenia 5: Różnice pomiędzy wersjami
Zadanie 3 |
Finito |
||
Linia 1: | Linia 1: | ||
Ćwiczenia z programowania zachłannego | Ćwiczenia z programowania zachłannego | ||
==Zadanie 1== | ==Zadanie 1 (Pokrycie punktów odcinkami jednostkowymi)== | ||
Podaj algorytm obliczający dla zadanego ciągu liczb rzeczywistych <math>a_1,\dots, a_n</math> opisujących punkty leżące na prostej, minimalną liczbę jednostkowych domkniętych odcinków na prostej pokrywających wszystkie punkty <math>a_1,\dots, a_n</math>. | Podaj algorytm obliczający dla zadanego ciągu liczb rzeczywistych <math>a_1,\dots, a_n</math> opisujących punkty leżące na prostej, minimalną liczbę jednostkowych domkniętych odcinków na prostej pokrywających wszystkie punkty <math>a_1,\dots, a_n</math>. | ||
Linia 60: | Linia 60: | ||
==Zadanie 2== | ==Zadanie 2 (Planowanie zajęć w salach)== | ||
Mamy dany zbiór N zajęć (każde zajęcia, mają swój czas rozpoczęcia i większy od niego czas zakończenia) oraz nieskończony zbiór sal. Należy policzyć najmniejszą liczbę sal potrzebną aby zaplanować wszystkie zajęcia. Oczywiście w danym momencie w jednej sali mogą się odbywać tylko jedne zajęcia. | Mamy dany zbiór N zajęć (każde zajęcia, mają swój czas rozpoczęcia i większy od niego czas zakończenia) oraz nieskończony zbiór sal. Należy policzyć najmniejszą liczbę sal potrzebną aby zaplanować wszystkie zajęcia. Oczywiście w danym momencie w jednej sali mogą się odbywać tylko jedne zajęcia. | ||
Linia 132: | Linia 132: | ||
==Zadanie 3== | ==Zadanie 3 (Dźwig)== | ||
Trójramienny dźwig ustawia kontenery na wagonach kolejowych. Wagony są ponumerowane kolejno 1, 2, ... . Na każdym wagonie można postawić co najwyżej jeden kontener. W jednym ruchu dźwig pobiera ze składowiska | Trójramienny dźwig ustawia kontenery na wagonach kolejowych. Wagony są ponumerowane kolejno 1, 2, ... . Na każdym wagonie można postawić co najwyżej jeden kontener. W jednym ruchu dźwig pobiera ze składowiska | ||
Linia 140: | Linia 140: | ||
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | {{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | ||
Idziemy po kolei od i=1 i jesli i-ty wagon jest wolny to wstawiamy i,i+p,i+p+q (zał. że p<=q) jesli sie da, wpp. i,i+q,i+p+q. | Idziemy po kolei od i=1 i jesli i-ty wagon jest wolny to wstawiamy i,i+p,i+p+q (zał. że p<=q) jesli sie da, wpp. i,i+q,i+p+q. Tylko dlaczego to jest dobrze? | ||
</div> | </div> | ||
</div> | </div> | ||
Linia 146: | Linia 146: | ||
{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | {{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | ||
'''procedure''' Dzwig(n,p,q:integer); | |||
// n,p,q>=1 | |||
'''var''' i:integer; | |||
wagony:'''array'''[1..n] '''of''' boolean; | |||
'''function''' wagon('''var''' j:integer):boolean; | |||
'''begin''' | |||
'''if''' j>n '''then''' | |||
wagon:=false | |||
'''else''' | |||
wagon:=wagony[j] | |||
'''end''' //wagon | |||
'''begin''' //Dzwig | |||
'''for''' i:=1 '''to''' n '''do''' wagony[i]:=false; | |||
'''if''' p>q '''then''' '''begin''' i:=p; p:=q; q:=i '''end'''; | |||
// teraz p<=q | |||
'''for''' i:=1 '''to''' n '''do''' '''begin''' | |||
'''if''' '''not''' wagony[i] '''then''' | |||
'''if''' '''not''' wagon(i+p) '''then''' | |||
writeln(i,' ',i+p,' ',i+p+q) | |||
'''else''' | |||
writeln(i,' ',i+q,' ',i+p+q) | |||
'''end''' | |||
'''end''' //Dzwig | |||
''Koszt czasowy'': koszt liniowy względem n. | |||
''Koszt pamięciowy'': kozst liniowy względem n. | |||
''Poprawność rozwiązania'': Należy zauważyć, że jeśli pole i jest wolne, a ruch (i,i+p,i+p+q) jest niemożliwy to (i,i+q,i+p+q) na pewno jest możliwy. Istotnie, ''zająć'' pole i+q mógł tylko wcześniejszy ruch (i-p, i-p+q,i+q). Ale skoro pole i jest wolne, więc rozpatrując pole i-p zostałby wybrany ruch (i-p,i,i+q), który zająłby i. Sprzeczność. Zatem o ile i jest wolne jeden z ruchów zaproponowanych przez program jest wykonalny. | |||
</div> | |||
</div> | |||
}} | |||
==Zadanie 4 (Uczta kinomana)== | |||
Dany jest zbiór N seansów, z podanymi godzinami rozpoczęcia i zakończenia. Ile maksymalnie seansów może obejrzeć zapalony kinoman, przy założeniu, że seansy zawsze ogląda w całości, nigdy nie ogląda dwóch filmów na raz i dowolnie szybko może przejść z jednego seansu na inny? | |||
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | |||
Należy zawsze wybierać te seanse, które najwcześniej się kończą. | |||
</div> | |||
</div> | |||
}} | |||
{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | |||
'''function''' Kinoman(N:integer; S:'''array'''[1..N] '''of''' '''record''' r,z:integer; tytul:string '''end'''):integer; | |||
// N>=1 | |||
'''var''' i,ile:integer; | |||
cz:real; | |||
'''begin''' | |||
sortZR(N,S); //sortowanie wg z, przy rownych z decyduje r | |||
ile:=1; | |||
i:=2; | |||
cz:=S[1].z; | |||
// ile to największa liczba filmów, które da się obejrzeć, by ostatni | |||
// skończył się w czasie <= cz | |||
'''while''' i<=N '''do''' '''begin''' | |||
'''if''' cz<=S[i].r '''then''' | |||
'''else''' '''begin''' | |||
// writeln('Kolejny film: ',s,', start: ',r,', koniec: ',z); | |||
cz:=S[i].z; | |||
ile:=ile+1; | |||
'''end'''; | |||
i:=i+1 | |||
'''end'''; | |||
Kinoman:=ile; | |||
'''end'''; //Kinoman | |||
''Koszt czasowy'': koszt sortowania (<math>N \log N</math>) + koszt | |||
liniowy względem <math>N</math>. | |||
''Koszt pamięciowy'': stały | |||
''Poprawność rozwiązania'': Każdy rozkład seansów kinomana można przerobić na zgodny z naszym rozwiązaniem, w taki sposób, żeby liczba seansów nie zmalała. Zauważmy, że jeśli w danym rozkładzie pierwszy seans kończy się później, niż ten wybrany przez algorytm, to można go zastąpić tym wybranym przez algorytm. Poza tym wszystkie seanse, które ominie nasz algorytm (przed wybraniem kolejnego seansu) nie mogą juz być w rozkładzie. Zatem po odrzuceniu tych seansów, dostajemy mniejszy zbiór seansów i przez indukcję pokazujemy, że nasz algorytm da optymalny wynik. | |||
</div> | |||
</div> | |||
}} | |||
==Zadanie 5 (Autostrada)== | |||
Jedziesz samochodem po autostradzie. Pełny bak benzyny pozwala na przejechanie n kilometrów. Wzdłuż autostrady rozmieszczonych jest M stacji benzynowych, których rozmieszczenie podane jest w tablicy B (odległośi kolejnych stacji od początku autostrady). Wypisz na których stacjach należy tankować, by przejechać do ostatniej stacji przy jak najmniejszej liczbie postojów na pozostałych stacjach benzynowych. | |||
Można założyć, że odległości stacji od siebie oraz od początku i końca trasy są mniejsze niż n. | |||
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | |||
Należy zawsze jechać tak daleko jak się da. | |||
</div> | |||
</div> | |||
}} | |||
{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | |||
'''procedure''' Autostrada(n:real; M:integer; B:'''array'''[1..M] '''of''' real); | |||
// n>0, M>=0, B posortowane | |||
// zakladając B[0]=0, dla i=1..M mamy B[i]-B[i-1]<=n | |||
'''var''' i:integer; | |||
t:real; | |||
'''begin''' | |||
t:=n; | |||
i:=1; | |||
// benzyny wystarczy '''do''' t | |||
'''while''' i<=M-1 '''do''' '''begin''' | |||
'''if''' B[i+1]>t '''then''' '''begin''' | |||
writeln('Kolejny postój: ',B[i]); | |||
t:=B[i]+n; | |||
'''end''' | |||
i:=i+1; | |||
'''end'''; | |||
writeln('Koniec: ',B[M]); | |||
'''end'''; //Autostrada | |||
''Koszt czasowy'': koszt liniowy względem M. | |||
''Koszt pamięciowy'': stały. | |||
''Poprawność rozwiązania'': Każdy rozkład postojów można zastąpić generowanym przez nasz algorytm bez zwiększania liczby postojów. | |||
Jeśli pierwszy planowany postój nie jest najdalszym możliwym, można go przesunąć. Następnie mamy do czynienia z sytuacją analogiczną jak sytuacja wyjściowa, tylko liczba stacji jest mniejsza. Zatem indukcyjnie można pokazać, że nasz algorytm da wynik optymalny. | |||
</div> | |||
</div> | |||
}} | |||
{{cwiczenie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | |||
Jak należy zmienić powyższą procedurę, gdybyśmy zrezygnowali z założenia o dobrym rozmieszczeniu stacji? Procedura powinna wypisywać "Nie da się" lub wskazywać stacje na których należy tankować. | |||
</div> | |||
</div> | |||
}} | |||
==Zadanie 6 (Wbijanie gwoździ)== | |||
Na nieskończenie długiej desce leżą nieskończenie cienkie (za to skończone) listewki. Jaka jest minimalna liczba gwoździ potrzebna do przybicia wszystkich listewek do deski? Zakładamy, że gwóźdź wbity w danym miejscu przybija wszystkie listewki przez które przechodzi, również jeśli jest wbity na samym końcu danej listewki. Początki i końce każdej z N listewek dane są w tablicy L rekordów o polach l i p typu real. Ponadto listewki nie moga mieć zerowej długości. | |||
{{wskazowka| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | |||
Należy posortować listewki wg końców i wbijać gwoździe tak daleko jak tylko się da. | |||
</div> | |||
</div> | |||
}} | |||
{{rozwiazanie| 1||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none"> | |||
'''function''' Wbijaj(N:integer; L:'''array'''[1..N] '''of''' '''record''' l,p:real '''end'''):integer; | |||
// N>0, dla i=1..N, L[i].l<L[i].p | |||
'''var''' i,ile:integer; | |||
g:real; | |||
'''begin''' | |||
sortujPL(N,L); | |||
ile:=1; | |||
g:=L[1].k; | |||
i:=2; | |||
// wszystkie listewki, ktore zaczynaja sie przed g sa przybite | |||
// wszystkie listewki, ktore zaczynaja sie po g nie sa przybite | |||
'''while''' i<=N '''do''' '''begin''' | |||
'''if''' L[i].l>=g '''then''' '''begin''' | |||
ile:=ile+1; | |||
g:=L[i].p; | |||
'''end'''; | |||
i:=i+1; | |||
'''end''' | |||
Wbijaj:=ile; | |||
'''end'''; | |||
''Koszt czasowy'': koszt sortowania (<math>N \log N</math>) + koszt liniowy względem <math>N</math>. | |||
''Koszt pamięciowy'': stały | |||
''Poprawność rozwiązania'': Każdy rozkład gwoździ można przerobić na zgodny z naszym rozwiązaniem, w taki sposób, żeby liczba gwoździ nie zwiększyła się. Istotnie, listwa, którą nasz algorytm wbije jako pierwszą musi być przybita jakimś gwoździem. Ponieważ żadna inna listwa nie kończy się wcześniej można ten gwóźdź przesunąć do końca listwy w prawo. Przybiliśmy w ten sposób wszystkie listwy, które mają z nią część wspólną, więc można je wszystkie usunąć. Pozostałe gwoździe przybijaja pozostałe listwy, a ponieważ jest ich mniej, więc z założenia indukcyjnego rozkład gwoździ można przesunąć tak, by był zgodny z naszym algorytmem. | |||
</div> | </div> | ||
</div> | </div> | ||
}} | }} |
Wersja z 01:45, 14 sie 2006
Ćwiczenia z programowania zachłannego
Zadanie 1 (Pokrycie punktów odcinkami jednostkowymi)
Podaj algorytm obliczający dla zadanego ciągu liczb rzeczywistych opisujących punkty leżące na prostej, minimalną liczbę jednostkowych domkniętych odcinków na prostej pokrywających wszystkie punkty .
Wskazówka 1
Rozwiązanie 1
Zadanie 2 (Planowanie zajęć w salach)
Mamy dany zbiór N zajęć (każde zajęcia, mają swój czas rozpoczęcia i większy od niego czas zakończenia) oraz nieskończony zbiór sal. Należy policzyć najmniejszą liczbę sal potrzebną aby zaplanować wszystkie zajęcia. Oczywiście w danym momencie w jednej sali mogą się odbywać tylko jedne zajęcia.
Wskazówka 1
Wskazówka 2
Rozwiązanie 1
Ćwiczenie 1
Zadanie 3 (Dźwig)
Trójramienny dźwig ustawia kontenery na wagonach kolejowych. Wagony są ponumerowane kolejno 1, 2, ... . Na każdym wagonie można postawić co najwyżej jeden kontener. W jednym ruchu dźwig pobiera ze składowiska trzy kontenery i ustawia je na wagonach o numerach i, i+p oraz i+p+q, albo na wagonach o numerach i, i+q oraz i+p+q (dla pewnych stałych p,q>=1). Dźwig trzeba zaprogramować tak, żeby załadował kontenerami pierwsze n wagonów pociągu (pociąg ma n+p+q wagonów).
Program dźwigu składa się z ciągu instrukcji. Każda z instrukcji opisuje jeden ruch dźwigu. Instrukcja programu ma postać trójki (x,y,z), gdzie 1 < x < y < z < n+p+q, i określa numery wagonów, na które dźwig ma ustawić kontenery. Jeżeli po wykonaniu programu na każdym spośród n pierwszych wagonów pociągu znajduje się dokładnie jeden kontener, to mówimy, że program jest poprawny.
Wskazówka 1
Rozwiązanie 1
Zadanie 4 (Uczta kinomana)
Dany jest zbiór N seansów, z podanymi godzinami rozpoczęcia i zakończenia. Ile maksymalnie seansów może obejrzeć zapalony kinoman, przy założeniu, że seansy zawsze ogląda w całości, nigdy nie ogląda dwóch filmów na raz i dowolnie szybko może przejść z jednego seansu na inny?
Wskazówka 1
Rozwiązanie 1
Zadanie 5 (Autostrada)
Jedziesz samochodem po autostradzie. Pełny bak benzyny pozwala na przejechanie n kilometrów. Wzdłuż autostrady rozmieszczonych jest M stacji benzynowych, których rozmieszczenie podane jest w tablicy B (odległośi kolejnych stacji od początku autostrady). Wypisz na których stacjach należy tankować, by przejechać do ostatniej stacji przy jak najmniejszej liczbie postojów na pozostałych stacjach benzynowych.
Można założyć, że odległości stacji od siebie oraz od początku i końca trasy są mniejsze niż n.
Wskazówka 1
Rozwiązanie 1
Ćwiczenie 1
Zadanie 6 (Wbijanie gwoździ)
Na nieskończenie długiej desce leżą nieskończenie cienkie (za to skończone) listewki. Jaka jest minimalna liczba gwoździ potrzebna do przybicia wszystkich listewek do deski? Zakładamy, że gwóźdź wbity w danym miejscu przybija wszystkie listewki przez które przechodzi, również jeśli jest wbity na samym końcu danej listewki. Początki i końce każdej z N listewek dane są w tablicy L rekordów o polach l i p typu real. Ponadto listewki nie moga mieć zerowej długości.
Wskazówka 1
Rozwiązanie 1