W poniższych zadaniach zdefiniuj opisane funkcje matematyczne.
Możesz, a nawet powinieneś, zdefiniować przydatne funkcje pomocnicze.
Opisz też sposób reprezentacji danych (np.\ punkt możemy reprezentować jako parę współrzędnych).
Rozwiązania poniższych zadań to proste procedury operujące na liczbach całkowitych.
Dla każdej procedury rekurencyjnej podaj jej specyfikację, tj. warunek wstępny i końcowy,
oraz uzasadnij jej poprawność.
Poprawność procedur rekurencyjnych można pokazać przez indukcję.
Napisz procedurę parzystość
wyznaczającą stopień parzystości danej liczby całkowitej.
Rozwiązania
sqrt
obliczającej sqrt x
\( = \lfloor\sqrt{x}\rfloor\)rzadkie : int → int
, która dla danej liczby naturalnej \(n\) zwróci najmniejszą rzadką liczbę naturalną większą od \(n\). Na przykład, dla \(n = 42 = 101010_2\) mamy \(\mathtt{rzadkie}\ 42 = 1000000_2 = 64\).rzadkie : int → int
, która dla danej liczby naturalnej \(n\) wyznaczy liczbę dodatnich liczb rzadkich, które nie przekraczają \(n\).rzadkie 42 = 20
.Rozwiązania poniższych zadań to proste procedury operujące na liczbach całkowitych.
Ich rozwiązanie wymaga zastosowania rekurencji ogonowej.
Dla każdej procedury rekurencyjnej podaj jej specyfikację, tj. warunek wstępny i końcowy,
oraz uzasadnij jej poprawność.
Poprawność procedur rekurencyjnych można pokazać przez indukcję.
Nie zapomnij o uzasadnieniu własności stopu.
p
, że \(\mathtt{p}\ f\ n = b - a + 1\) (dla \(a\) i \(b\) jak wyżej).maksima
, która dla danych liczb \(l\) i \(p\) (\(l \le p\)) obliczy ile lokalnych maksimów ma funkcja \(f\) w przedziale \([l, p]\).
Ćwiczenie programistyczne na listy:
last
, której wynikiem jest ostatni element listy. head
i tail
, które dla zadanej listy \(l\) i liczby całkowitej \(n\)head
i tail
w Uniksie.)tail (head l n) 1
?
shuffle: α list → α list → α list
, która dla danych dwóch list postaci \([x_1; x_2; \dots; x_n]\) oraz \([y_1; y_2; \dots; y_m]\) wyznaczy listę postaci \([x_1; y_1; x_2; y_2; \dots]\). Jeżeli jedna z list jest dłuższa, to jej końcowe elementy trafiają na koniec listy wyikowej.shuffle [3; 2; 8; 1; 9; 3; 6] [5; 7; 0] = [3; 5; 2; 7; 8; 0; 1; 9; 3; 6].
Napisz procedurę tails : α list → α list list
,
która dla danej listy tworzy listę wszystkich jej sufiksów, uporządkowaną wg ich długości (wybrać, czy rosnąco, czy malejąco).
wysun : int list -> int list
, która dla danej listy posortowanej niemalejąco wybierze wszystkie jej elementy występującewysun [1;2;2;3;4;5;5;6;6;6;7] = [2;2;5;5;6;6;6;1;3;4;7]
bonifacy : int -> int list -> int
, która dla liczby naturalnej n (n ≥ 0) oraz co najmniej trzyelementowej zerojedynkowej listy \([b_0; \dots; b_{k−1}]\) obliczy n-tą liczbę wyznaczonego przez tę listę ciągu Bonifacego.
zsumuj
, która dla danej niemalejącej listy dodatnich liczb całkowitychpodziel : int list → int list list
, która dla danej listy postaciPrzykład: \(\mathtt{podziel}\, [2; 3; 1; 6; 5; 4; 7; 9; 10; 11; 8] = [[2; 3; 1]; [6; 5; 4]; [7]; [9; 10; 11; 8]]\).
mieszaj
, która wywołana dla danej listy, obliczy listę powstałą przeztrojki : int list → (int} * int * int) list
,malo [-42, -12, -8, -1, -1, 5, 15, 60] = 2
.
Możesz założyć, że dana lista \(l\) zawiera przynajmniej dwa elementy.
fit 42 [-28, -25, -15, -1, 4, 8, 15, 60] = 1
, ponieważ \(|42 - 28 - 15| = 1\).
Rozpatrujemy tabele, których wiersze są uporządkowane ściśle rosnąco, a kolumny ściśle malejąco.
Napisz procedurę znajdz : int list list → int → (int * int) list
, która znajduje wszystkie pozycje, na
jakich w takiej tabeli znajduje się podana liczba.
Napisz procedurę dekompresuj : int list → int list
dekompresującą zadaną listę.
Możesz założyć, że lista skompresowana nie zawiera zer.
Podaj specyfikację (warunek początkowy i końcowy) wszystkich definiowanych procedur i uzasadnij zwięźle ich pełną poprawność.
W przypadku rekurencyjnych procedur iteracyjnych warunek początkowy musi zawierać niezmiennik iteracji.
dekompresuj [1; 3; 3; 9; 42; 3];; - : int list = [1; 2; 2; 5; 11; 11; 2]
palindrom : α list → int
,podziel : int → α list → α list list
,Przykład: \(\mathtt{podziel}\ 3\ [1;2;3;4;5;6;7] = [[1; 4; 7]; [2; 5]; [3; 6]] \).
Jaś wymyślił sobie następującą zabawę.
Mając do dyspozycji pewien zestaw krążków zastanawia się, na jakiej głębokości zatrzymałby się ostatni z nich,
gdyby wrzucać je kolejno do rurki centralnie (czyli dokładnie w jej środek).
Każdy kolejny krążek po wrzuceniu spada dopóki się nie zaklinuje (czyli nie oprze się o walec, w którym wycięty jest
otwór o mniejszej średnicy niż średnica krążka), albo nie natrafi na przeszkodę w postaci innego krążka lub dna rurki.
Napisz procedurę krążki : int list → int list → int
, która na podstawie listy średnic
otworów w kolejnych walcach tworzących rurkę, oraz listy średnic kolejno wrzucanych krążków obliczy głębokość, na której zatrzyma się
ostatni wrzucony krążek (lub 0 jeśli nie wszystkie krążki zmieszczą się w rurce).
Rozwiązania
mnóż : float list → float list → float list
mnożącą wielomiany.
Uwaga: Pusta lista reprezentuje zerowy wielomian.
Ćwiczenie programistyczne na drzewa i inne struktury danych:
type α tree = Node of α tree * α * α tree | Null;;
Drzewo nazywamy ultralewicowym jeśli głębokości kolejnych liści (Null
), od lewej do prawej, tworzą ciąg nierosnący.
Napisz procedurę ultraleft : α tree → bool
, która sprawdza czy dane drzewo jest ultralewicowe.
type α tree = Node of α tree * α * α tree | Nil;;
Napisz procedurę liscie : α tree → α list
, która tworzy listę wartości znajdujących się w liściach (Node
) drzewa.
potnij
, która dla danego predykatu \(p\) typu \(\alpha \to \mathtt{bool}\), oraz drzewa \(t\) typu \(\mathtt{\alpha\ tree}\), zwróci następujący wynik.potnij p t
powinno zwrócić listę tych drzew (w dowolnej kolejności).
rozcięcie
, która znajduje taką krawędź w danym drzewie binarnym, że po jej usunięciu drzewotype tree = Node of tree * int * tree | Null;;
type expr = And of expr * expr | Or of expr * expr | Not of expr | Value of bool;;
Warianty And
, Or
i Not
reprezentują odpowiednie operacje logiczne,
natomiast wariant Value
reprezentuje wartość logiczną true
lub false
.
Napisz funkcję wartościowania : expr → int
,
która dla danego wyrażenia policzy na ile różnych sposobów można przypisać wszystkim
wariantom Value
wartości logiczne, tak aby wartość całego wyrażenia wyliczała się do true
.
Przykład: wartościowania Or(Value true, Value false) = 3
,
gdyż wyrażenie wyliczy się do true
, w trzech przypadkach:
Or(Value true, Value true)
, Or(Value true, Value false)
, Or(Value false, Value true)
.
type 'a tree = Node of 'a * 'a tree * 'a tree | Null;;
Skosokość drzewa jest zdefiniowana w następujący sposób:
Null
wynosi 0, Dla danego drzewa wolno nam w dowolnych jego węzłach zamieniać miejscami lewe i prawe poddrzewa.
Napisz procedurę \(\mathtt{skosokosc}: \alpha\ \mathtt{tree} \to \alpha\ \mathtt{tree}\), która przekształca dane drzewo tak, aby zminimalizować jego skosokość.
Na przykład, dla:
t = Node(5, Node(4, Null, Node(2, Null, Null)), Node(6, Node(1, Null, Null), Node(3, Null, Null) ) ) skosokosc t = Node(5, Node(6, Node(1, Null, Null), Node(3, Null, Null) ), Node(4, Node(2, Null, Null), Null) )
Skosokość tak uzyskanego drzewa wynosi 6.
type tree = Node of (int * tree list);;
Każdy pracownik charakteryzuje się pewną "towarzyskością" wyrażoną liczbą dodatnią.
Napisz program, który dobierze gości tak, aby:
Jak zapewnić, aby szef firmy był na przyjęciu?
type tree = Node of tree * tree | Null
.
Odległością między dwoma wierzchołkami (Node
) w drzewie nazywamy minimalną
liczbę krawędzi jakie trzeba przejść z jednego wierzchołka do drugiego.
Średnicą drzewa nazwiemy maksymalną odległość między dwoma węzłami (Node
) w drzewie.
Przyjmujemy, że średnica pustego drzewa (Null
) jest równa 0.
Napisz procedurę średnica : tree → int
, która oblicza średnicę danego drzewa.
Rozwiązania
type 'a drzewo = Node of 'a * 'a drzewo * 'a drzewo | Null
Napisz procedurę polowa:'a drzewo -> 'a drzewo
, która znajduje w zadanym drzewie taki węzeł (Node
), który jest przodkiem jak najmniejszej liczby liści, ale przynajmniej połowy wszystkich liści drzewa.
type tree = Node of int * tree * tree | Leaf;;
Napisz procedurę \(\mathtt{odchudzanie}: \mathtt{tree} \to \mathtt{tree}\), która mając dane drzewo binarne, zwraca drzewo powstałe przez usunięcie z niego takich poddrzew
(zastępując Node(...)
przez Leaf
) aby suma elementów w powstałym drzewie była jak największa.
type drzewo = Node of α * α drzewo * α drzewo | Null
Napisz procedurę środek : α drzewo → α drzewo
, która znajduje w zadanym drzewie taki
węzeł (Node
), dla którego maksymalna spośród jego odległości od liści jest jak najmniejsza.
Wynikiem tej procedury powinno być poddrzewo zakorzenione w wyznaczonym węźle.
Co się zmieni, jeżeli będziemy chcieli znaleźć wierzchołek, dla którego
minimalna spośród jego odległości do liścii jest jak największa?
type tree = Node of int * tree * tree | Null
Przekrojem drzewa nazwiemy dowolny taki zbiór jego wierzchołków (Node
), że na każdej ścieżce
od korzenia do liścia (Null
) znajduje się dokładnie jeden wierzchołek należący do przekroju.
Napisz procedurę cut : tree → int
, która dla danego drzewa wyznaczy najmniejszą możliwą sumę liczb
znajdujących się w wierzchołkach tworzących przekrój danego drzewa.
type α tree = Node of α * α tree list;;
Napisz procedurę \(\mathtt{liscie} : \alpha\ \mathtt{tree} \to \mathtt{int~list}\), która dla danego drzewa liczy ile w tym drzewie jest liści na poszczególnych głębokościach i zwraca listę liczb postaci \([g_0; g_1; \dots; g_h]\), gdzie \(g_i\) to liczba liści znajdujących się na głębokości \(i\), a \(h\) to wysokość drzewa.
type α tree = Node of α * α tree list;;
Ścieżkę w drzewie nazwiemy rosnącą, jeżeli wartości w węzłach na tej ścieżce, w kierunku od korzenia w dół, są rosnące.
Napisz procedurę rosnaca: int tree → int list
, która znajdzie w danym drzewie najdłuższą ścieżkę rosnącą i zwróci wartości znajdujące się na niej (w kolejności od korzenia w dół). (Uwaga: szukana ścieżka nie musi zaczynać się w korzeniu i nie musi kończyć się w liściu.)
Rozwiązania
type α tree = Node of α * α tree list;;
Napisz procedurę nieparzyste: α tree → int
, która dla danego drzewa policzy ile jest w nim poddrzew zawierających nieparzystą liczbę wierzchołków.
type tree = Node of tree * int * tree | Null;;
Napisz procedurę czapeczka : tree → tree → int
, która obliczy na ilu poziomach, idąc od góry,
dane drzewa są identyczne, tzn. na tych poziomach drzewa mają ten sam kształt, a w odpowiadających sobie wierzchołkach są takie same liczby.
[D.L.Parnas, On the Criteria To Be Used in Decomposing Systems into Modules, CACM 12 (15), 1972]
Rozważmy następujący problem. Należy napisać program, który:
Podaj jak byś podzielił program na moduły.
Wymyśl zestaw realistycznych modyfikacji, jakie należy wprowadzić (a jeszcze lepiej poproś o to kolegę) i sprawdź, jak sprawuje się wymyślony przez Ciebie podział na moduły.
Zdefiniuj sygnatury/struktury odpowiadające podanym poniżej pojęciom.
Staraj się wykorzystać zdefiniowane wcześniej pojęcia.
sup
i inf
.
sup
i inf
.sig type α tree = Node of α tree * α * α tree | Null type α walk make : α tree → α walk goleft : α walk → α walk goright : α walk → α walk goup : α walk → α walk lookup : α walk → α tree exception OutsideTree end
Wywołanie make d
powinno konstruować przechadzkę, w której znajdujemy się w korzeniu drzewa d
.
Wywołanie goleft p
powinno konstruować przechadzkę powstałą przez przejście do lewego poddrzewa.
Analogicznie powinny działać procedury goright
i goup
.
Procedura lookup
powinna zwrócić poddrzewo zaczepione w wierzchołku drzewa, w którym aktualnie jesteśmy.
Podczas przechadzki po drzewie możemy przebywać jedynie w wierzchołkach Node _
.
Jeśli nastąpi próba wejścia do Null
'a lub wyjścia ,,ponad'' korzeń, należy podnieść wyjątek OutsideTree
.
Ćwiczenia na procedury wyższych rzędów, ale bez standardowych procedur wyższych rzędów przetwarzających listy:
iterate 2 (function x -> x * (x+1)) 2 iterate 3 (function x -> x * (x+1)) 1
rozrysowując ramki.
W przypadku szybszego potęgowania funkcji co tak na prawdę jest obliczane szybciej: funkcja wynikowa, czy jej wartość?
Rozwiązania
Zaimplementuj procedurę odwrotnosc
, której wynikiem dla parametru \(f\) będzie przybliżenie \(f^{-1}\) z dokładnością
zadaną przez stałą epsilon
(czyli jeśli \(g = (\mathtt{odwrotnosc}\ f)\), to \(\forall x\ |g(x) - f^{-1}(x)| \le \mathtt{epsilon}\)).
Ćwiczenia na listy z elementami procedur wyższych rzędów:
exists
, która dla danego predykatu i listy sprawdzi, czy na liście jest element spełniający predykat.non: (α → bool) → (α → bool)
.exists
zdefiniuj procedurę forall
,exists
nadal powoduje, że przeglądane są tylko niezbędne elementy listy?
append
za pomocą fold_right/fold_left
.
map
i flatten
procedurę heads
,sumy : int list → int list
, która dla danej listy \([x_1;\dots; x_n]\)sumy [1; 5; 2; 7; 12; 10; 5] = [1; 6; 8; 15; 27; 37; 42]
.codrugi : α list → α list
, która z danej listy wybiera co drugi element (zaczynając od drugiego).codrugi [1; 2; 3; 4; 5] = [2; 4]
.
zlecenia [(-1, 1); (2, 2); (3, 3); (4, 2); (10, 2)] = [1; 2; 4; 5; 2]}
.podzial : α list → α list list
, która daną listę podzieli napodzial [3;2;2;5;7;5;4;4;3;1] = [[3;2];[2;5;7;5;4];[4;3;1]]
.prextrema [-2; 1; 0; 1; 3; 2; -1; 5; 4; -3; 2; 1; 7] = [-2; 1; 3; 5; -3; 7]
wzrost [3; 4; 0; -1; 2; 3; 7; 6; 7; 8] = [-1; 2; 3; 7] wzrost [] = []
type kolor = Czerwona | Zielona
.kulki [Czerwona, Zielona, Zielona, Zielona, Zielona, Czerwona, Czerwona, Zielona] = 2
.
Napisz taką procedurę dopoki : α list → (α → bool) → (α → bool) → int list
, że wynikiem
\(\mathtt{dopoki}\ [x_1; x_2; \dots; x_n]\ p\ q\) jest lista tych chwil w czasie, w których zachodzi \(p\) dopóki \(q\).
Na przykład, dla następujących \(p\) i \(q\):
\(i\) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
\(p\ x_i\) | false |
true |
true |
true |
false |
false |
true |
true |
true |
false |
false |
false |
\(q\ x_i\) | false |
false |
true |
false |
true |
false |
false |
true |
false |
false |
true |
false |
Ekstremum oznacza minimum lub maksimum.
Napisz procedurę ekstrema :int list → int
, która dla danej listy policzy ile jest na niej ekstremów.
Rozwiązania
Napisz procedurę inc : int list → int list
, która dla danej listy będącej reprezentacją liczby \(x\),
wyznaczy reprezentację liczby \(x+1\).
Przyjmujemy, że lista pusta reprezentuje 0.
plateau : α list → int
, która oblicza długość najdłuższego stałego (spójnego) fragmentu danej listy.
@
i filter
uproszczoną wersję algorytmu quick-sort. Napisz procedurę usrednienie : float list → float list
, która dla danej listy obliczy jej uśrednienie.
od_końca_do_końca : int list → int
, która dla danej niepustejfold_left
/fold_right
) procedurę tails : α list → α list list
,: (α list * int * int) list}
reprezentuję listędekompresja : (α list * int * int) list → int → α
, którakompresuj : int list → int list
kompresującą zadaną listę.kompresuj [1; 2; 2; 5; 11; 11; 2];; - : int list = [1; 6; 9; 42; 3]
prawie [3; 2; -2; 0; 42; 22; -12; 15; -4] = 4
.[2; -2; 0; 42]
i [22; -12; 15; -4]
.
winda: int → int list → int
, która mając dane \(w\) oraz listę ciężarów kolejnych osób czekających na windę policzy minimalną liczbę kursów windy potrzebnych do obsłużenia czekających.buduj_permutacje : α list list → α → α
,buduj_permutacje
\([c_0; \dots; c_k]\ x = x\).let p = buduj_permutacje [[2; 1]; [8; 3; 4]; [5; 7; 6; 10]; [11]];; map p [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12];; -: int list = [2; 1; 4; 8; 7; 10; 6; 3; 9; 5; 11; 12]
podzial : int list → int list list
, która dla danej listy liczb całkowitychPrzykład:
podzial [1;3;0;-2;-2;-4;9] = [[1; 3]; [0]; [-2;-2;-4]; [9]]
monotons [2; 3; 3; 5; 0; -1; -7; 1; 3; 5; 5; 2; 4; 6] = 4
.[2; 3; 3]
, [5; 0; -1; -7]
, [1; 3; 5; 5]
, [2; 4; 6]
.
prefiksy [0;1;2;3;0;5;6;0;1] = [[0]; [0;1;2;3;0]; [0;1;2;3;0;5;6;0]]
Na przykład: transpose [[1; 2]; [5; 3]; [0; 1]] = [[1; 5; 0]; [2; 3; 1]]
Rozwiązania
type symbol = | Liczba of int | Plus | Minus | Razy | Podziel | Nawias_Otw | Nawias_Zam
Masz daną listę symboli tworzących poprawne wyrażenie arytmetyczne. Napisz procedurę \(\mathtt{kalkulator}: \mathtt{symbol~list} \to \mathtt{int}\), która obliczy wartość wyrażenia.
Przyjmij, że, o ile nawiasy nie wymuszają innej kolejności, operacje arytmetyczne wykonujemy od lewej do prawej.
Przykład:
kalkulator [Nawias_Otw; Liczba 5; Plus; Liczba 4; Razy; Liczba 2; Plus; Liczba 3; Nawias_Zam; Razy; Liczba 2] = 42
Ćwiczenia na drzewa z elementami procedur wyższych rzędów:
tree
i procedura fold_tree
:
type 'a tree = Node of 'a * 'a tree list;; let rec fold_tree f (Node (x, l)) = f x (map (fold_tree f) l);;
Użyj procedury fold_tree
do zaimplementowania:
preorder/postorder : 'a tree -> 'a list
, która przekształca dane drzewo w listę jego elementów w porządku pre-order/post-order (zwróć uwagę na efektywność).bin_tree
i procedura fold_bin_tree
:
type 'a bin_tree = Node of 'a bin_tree * 'a * 'a bin_tree | Null;; let rec fold_bin_tree f a t = match t with Null -> a | Node (l, x, r) -> f x (fold_bin_tree f a l) (fold_bin_tree f a r);;
Użyj procedury fold_bin_tree
do zaimplementowania:
float tree
),map_bin_tree
-- odpowiednika procedury map_tree
dla drzew binarnych, sprawdz
o treści:
let sprawdz (a:int) = let n = ??? in if a < n then -1 else if a = n then 0 else 1;;
W tej implementacji pod ???
została ukryta pewna liczba całkowita.
Napisz funkcje znajdz
, która odwołując się do funkcji sprawdz
, znajdzie tę liczbę całkowitą.
Podaj złożoność czasową i pamięciową rozwiązania.
Uwaga: Zakładamy, że typ int
reprezentuje dowolne liczby całkowite.
W szczególności nie można zakładać, że typ int
jest skończony i tym samym używać stałych takich jak max_int
.
hanoi: int list → int → int
, która dla zadanej konfiguracji krążków oraz słupka, na Słupki są reprezentowane jako liczby całkowite od 1 do 3.
Konfiguracja to lista numerów słupków, na których mają się znaleźć krążki, w kolejności od największych krążków do najmniejszych.
W poniższych zadaniach istotne jest posortowanie odpowiednich list:
Napisz procedurę słupki : int list → int
, która dla danej listy początkowych wysokości słupków
obliczy minimalną liczbę uderzeń młotka potrzebnych do wyrównania wysokości słupków.
elementy : α list → int list → α list
, która dla list \([x_1; x_2; \ldots, x_n]\) itrójkąt : int list → bool
, która dla danej listy \([x_1; x_2; \dots; x_n]\) dodatnich liczb Podaj złożoność czasową i pamięciową swojego rozwiązania.
(Uwaga: Jeżeli liczby całkowite mają ograniczony zakres, to można to zadanie rozwiązać w stałym czasie.)
przedział : int list → int → int
, która dla danej listy \([x_1;\dots; x_n]\), oraz dla liczby całkowitej Przykład: przedział [2; -2; 5; -1; 11; 8; 4; 5; 8; 7] 2 = 6
.
Rozwiązania
przekładaniec
, której wynikiem jest taka permutacja \([x_{p_1}; x_{p_2}; \dots; x_{p_n}]\) danej listy,pierwsze : int list → int list
, która zwróci taką jej spójną podlistę, że:
Rozwiązując poniższe zadania zwróć uwagę na efektywność algorytmów.
W większości zadań należy użyć techniki kosztu zamortyzowanego.
rotate
z wykładu). Napisz procedurę \(\mathtt{zlewki}:\mathtt{float~list} \to \mathtt{int} \to \mathtt{float}\),
która dla danej listy zawierającej liczby \([|x_1; \dots; x_n|]\) oraz liczby \(k\) określa
określa ile jest wody w najmniej wypełnionym niepustym kubeczku po wykonaniu \(k\) operacji przelewania.
type pora = Wiosna | Lato | Jesień | Zima
.pory [|Lato; Wiosna; Zima; Jesień; Lato; Zima; Wiosna; Jesień; Lato|] = 6
.Jesień, Zima, Wiosna, Lato
.
Przykład: Poniżej podane są temperatury i czym będzie pokryta sadzawka (od góry) w kolejne dni:
Napisz procedurę \(\mathtt{sadzawka}: \mathtt{int~list} \to \mathtt{int~list}\), która dla danej listy temperatur zwróci listę reprezentującą kolejne warstwy pokrywające sadzawkę po tym okresie – liczby ujemne reprezentują lód, dodatnie wodę, a ich wartość bezwzględna grubość warstwy.
Dla powyższego przykładu, poprawnym wynikiem jest \([-6, 4, -2]\).
init : int → α max_queue
-- tworzy nową pustą kolejkę z określonym parametrem \(k\), put : α max_queue → α → α max_queue
-- wkłada element do kolejki, get_max : α max_queue → α
-- zwraca maksimum z \(k\) ostatnich elementów włożonych do kolejki. Wszystkie operacje na kolejce powinny działać w stałym czasie zamortyzowanym.
kmax : int → int list → int list
, dla której wynikiem kmax
\(k\) \(l\) jest podlistawidoczne
, która obliczy ile elementów ciągu jest widocznych z kolejnych jego elementów.widoczne [1; 8; 5; 6; 4] = [1; 3; 2; 3; 1]
.
Napisz procedurę \texttt{prostokat: int list → int}, która dla danej tablicy wyznaczy maksymalną powierzchnię prostokąta (o bokach równoległych do boków figury), który można wpisać w figurę opisaną przez tablicę.
różnica : int list → (int * int)
, która dla danej listy wyznaczy taką parę liczb \((i,j)\), że:
Jeżeli takie \(i\) i \(j\) nie istnieją, to poprawnym wynikiem jest (0,0).
Liczby reprezentujemy jako listy zer i jedynek.
Zaimplementuj dodawanie w systemie Zeckendorfa.
Zaprojektuj i zaimplementuj podane funktory:
t
konstruujet
).
Uwaga: Zadania oznaczone [SICP] są mocno inspirowane zadaniami i materiałem z tejże książki, choć nie ma w niej mowy o funktorach.
Ćwiczenia na konstrukcje imperatywne:
Counter
o następującej sygnaturze:
module type COUNTER = sig type counter val make : unit -> counter val inc : counter -> int val reset : unit -> unit end;;
Procedura make
tworzy nowy licznik o początkowej wartości 0.
Procedura inc
zwiększa licznik o 1 i zwraca jego nową wartość.
Procedura reset
ustawia wartość wszystkich liczników na 0.
Podaj złożoność czasową i pamięciową ciągu \(m\) operacji, spośród których \(n\) to operacje make
.
cykl [|2; 1; 0; 5; 6; 4; 3; 8; 7|] = 4
Twoja procedura powinna działać w stałej pamięci dodatkowej.
Natomiast może modyfikować daną tablicę.
type α tree = Node of α * α tree * α tree * α tree ref | Null;;
Null
.)fastryguj : α tree → unit
, która sfastryguje dane drzewo.
w_lewo : α tree → unit
, która w każdym węźle drzewa ustawia referencję tak, aby wskazywały na węzeł (Node
) znajdujący się na tej samej głębokości w drzewie i najbliżej w lewo od danego węzła. W przypadku skrajnie lewych węzłów, referencja powinna wskazywać na Null
.
potomek : α tree → unit
, która w każdym węźle ustawi referencję na najgłębiej położony węzeł (Node
) będący jego potomkiem.
Node(x, left, right, _)
wartości w poddrzewie left
są mniejsze lub równe x
, a wartości w poddrzewie right
są większe równe x
.fastryga: α tree → unit
, która mając dane drzewo porządkowe tak ustawi w nim referencje, że węzły zawierające takie same wartości będą połączone w listy cykliczne.diagonal: (float * float) array → float
, która wyznaczy najkrótszą z przekątnych prostokątów.
type 'a heap = Node of 'a heap * 'a * 'a heap | Null
Sam stóg nie jest dany, natomiast mamy daną tablicę z liczbami znajdującymi się w węzłach, w kolejności zgodnej z obejściem infiksowym stogu.
(Obejście infiksowe, to obejście zgodnie z rekurencyjną zasadą: najpierw lewe poddrzewo, potem korzeń a potem prawe poddrzewo.)
Napisz procedurę \(\mathtt{rekonstrukcja}: \mathtt{int~array} \to \mathtt{int~heap}\), która mając daną tablicę z obejściem stogu odtworzy go.
rotacja\,:\,char array -> int -> unit
, która rotuje daną tablicę o zadaną liczbę miejsc cyklicznie w prawo, tzn.:rotacja [|'a'; 'l'; 'a'; 'm'; 'a'; 'k'; 'o'; 't'; 'a'|] 4}
[|'k'; 'o'; 't'; 'a'; 'a'; 'l'; 'a'; 'm'; 'a'|]
.
slowa [|'a'; 'b'; 'b'; 'a' ;'b'; 'a'; 'c'; 'a'; 'b'; 'a'; 'b'; 'a'; 'b'|] = 6
.
minmax : int array -> int * int
, która znajduje minimum i maksimum w takiej tablicy.
Napisz procedurę \(\mathtt{rejs}: \mathtt{int} \to (\mathtt{int} * \mathtt{int})\ \mathtt{list} \to \mathtt{int}\), która mając daną liczbę \(k\) oraz informacje o dostępności kolegów Tomka zwróci maksymalną długość rejsu. Jeżeli rejsu nie da się zorganizować, to poprawnym wynikiem jest 0.
Na przykład: \(\mathtt{rejs}\ 2\ [(12, 36); (48, 100); (28, 70); (50, 80); (0, 69); (25, 30)] = 42\).
Rozwiązując to zadanie nie wolno Ci tworzyć żadnych własnych procedur rekurencyjnych.
Wolno natomiast korzystać z pętli i innych konstrukcji imperatywnych.
Podaj złożoność czasową i pamięciową swojego rozwiązania.
Rozwiązując to zadanie nie wolno Ci tworzyć żadnych własnych procedur rekurencyjnych.
Zamiast tego powinieneś użyć konstrukcji imperatywnych.
type 'a option = None | Some of 'a type 'a elem = {v: 'a; mutable next: 'a lista} and 'a lista = 'a elem option
type elem = { x: int; mutable prev: elem list };; type lista = elem list;;
Napisz procedurę \(\mathtt{ustaw} : \mathtt{lista} \to \mathtt{unit}\), która dla danej listy \([x_1; x_2; \dots; x_n]\) typu lista
, tak ustawia pola prev
, aby (dla \(i=1,2,\dots, n\)) prowadziło ono z elementu \(x_i\) do listy zaczynającej się w elemencie \(x_{n-i+1}\).
Skarbonki są ponumerowane od 0 do \(n-1\).
Na podstawie tablicy \(a\) (rozmiaru \(n\)), takiej, że \(a.(i) = \) numer skarbonki, w której znajduje się kluczyk do skarbonki
numer \(i\), oblicz minimalną liczbę skarbonek, które należy rozbić, tak aby dostać się do zawartości wszystkich skarbonek.
Zaprojektuj algorytm, który na podstawie opisu tego która małpka trzyma którą, oraz na podstawie opisu łapek puszczanych w
kolejnych chwilach, dla każdej małpki wyznaczy moment, kiedy spadnie ona na ziemię.
kolory: int * int list → int
,Pola niezerowe stykające się bokami tworzą jedno złoże. Odwierty znajdujące się w danym złożu pozwalają pobrać tyle gazu ile pól obejmuje złoże, po czym ilość gazu we wszystkich polach złoża maleje o 1. Może to spowodować zmniejszenie lub podzielenie się złoża. Dalej odwierty pozwalają pobierać gaz z tak zmienionych złóż.
Napisz procedurę \(\mathtt{gaz}: \mathtt{int~array~array} \to \mathtt{int}\), która obliczy łączną ilość gazu, jaką wydobędą odwierty.
Dwaj gracze, biały i czarny, grają w grę hex.
Zajmują oni na przemian wolne pola na planszy. Zaczyna gracz biały.
Gracz biały stara się połączyć swoimi polami lewy i prawy brzeg planszy, a gracz czarny górny i dolny brzeg planszy.
Wygrywa gracz, który jako pierwszy połączy odpowiednie brzegi planszy, w ten sposób, że z jednego brzegu na drugi
będzie można przejść przez sąsiadujące pola zajęte przez danego gracza.
Napisz procedurę hex : int → (int * int) list → (bool * int)
, która na podstawie wielkości planszy \(n\),
oraz listy współrzędnych (rząd, pozycja w rzędzie) kolejno zajmowanych przez graczy pól określi, czy wygrał gracz biały
(true
), czy czarny (false
) i w którym ruchu.
Napisz procedurę biura : int → int * int list → int
, która na podstawie liczby pracowników \(n\) oraz listy par pracowników
posiadających nawzajem swoje numery telefonów \(l=[(a_1,b_1);\dots; (a_m,b_m)]\), wywołana jako \(\mathtt{biura}\ n\ l\), obliczy liczbę biurowców.
Rozwiązując to zadanie przyjmij, że \(m=O(n)\).
przedzialy: int → (int * int * int) list → int
, która dla danego \(n\) oraz ciągu trójek oblicza takie \(k\).
coto
i udowodnij to.
x := 0; y := 1; while !y <= n do x := !x - !y; y := !y - !x done;
length
a -- badać wielkość tabicy n, Napisz procedurę zamiany : int array → unit
, która posortuje daną tablicę
(tj. przekształci ją w permutację identycznościową) wykonując minimalną możliwą liczbę zamian.
Podaj niezmienniki pętli oraz odpowiednie funkcje miary.
Nie muszą one mieć postaci formuł, ale muszą być ściśle określone.
Udowodnij pełną poprawność programu.
i := 0; d := 1; s := 1; while !s <= !x do d := !d + 2; s := !s + !d; i := !i + 1 done;
\(\{ !i = \lfloor{\sqrt{!x_0}}\rfloor \}\)
let north = 0 and east = 1 and south = 2 and west = 3;;
Układ ulic jest dany w formie trójwymiarowej tablicy wartości logicznych ulice
: \(\mathtt{ulice}.(i).(j).(k)\)
określa, czy z punktu o współrzednych \((i,j)\) można przejechać w kierunku k jedną jednostkę odległości.
Można założyć, że tablica ta uniemożliwia wyjechanie poza obszar \(\{0,\dots,m-1\} \times \{0,\dots,n-1\}\).
Członkowie Klubu Prawoskrętnych Kierowców na skrzyżowaniach jeżdżą prosto lub skręcają w prawo.
Sprawdź, czy z punktu \((0,0)\) prawoskrętny kierowca może dojechać do punktu \((m-1, n-1)\).
Masz daną prostokątną tablicę zawierającą dodatnie liczby całkowite. Jest to mapa sadzawki, a liczby reprezentują moment, w którym lód w danym miejscu pęka.
Napisz procedurę \(\mathtt{sadzawka}: \mathtt{int~array~array} \to (\mathtt{int} * \mathtt{int}) \to \mathtt{int}\), która mając daną taką tablicę oraz współrzędne miejsca, w którym bawi się Jaś, wyznaczy moment, w którym Jaś straci możliwość wyjścia na brzeg (bo albo zostanie odcięty od brzegu spękanym lodem, albo wpadnie do wody).
Możesz założyć, że:
bool array array
.true
reprezentują ląd, a false
wodę. Wyspy na oceanie są wyspami rzędu 1.
Na wyspach rzędu 1 mogą znajdować się jeziora rzędu 1, na nich mogą znajdować się wyspy rzędu 2 itd.
Ogólnie:
Pola wody przylegające do siebie bokami lub rogami należą do tego samego jeziora (lub oceanu).
Pola lądu przylegające do siebie bokami należą do tej samej wyspy.
Napisz procedurę \(\mathtt{wyspa}: \mathtt{bool\ array\ array} \to \mathtt{int}\), która dla danej mapy zwróci maksymalny rząd wyspy na mapie.
Jeżeli na oceanie nie ma żadnej wyspy, to procedura powinna zwrócić 0.
Przykład: 69.793N, 108.241W.
Wyznacz podział pracowników na grupy.
e
wartości logicznych; w grafie mamy krawędź \(u\!\!\to\!\!v\) wtw., gdy \(\mathtt{e}.(u).(v)\)). Napisz procedurę zdominowani : bool array array -> int
, która na podstawie tablicy opisującej graf
obliczy liczbę wierzchołków, dla których istnieją wierzchołki je dominujące.
(int * bool) array array
. Miasto zostało całkowicie zalane.
Żeby je osuszyć należy w kotlinie rozmieścić pewną liczbę pomp.
Każda z pomp wypompowuję wodę aż do osuszenia kwadratu jednostkowego, na którym się znajduje.
Osuszenie dowolnego kwadratu pociąga za sobą obniżenie poziomu wody lub osuszenie kwadratów jednostkowych, z
których woda jest w stanie spłynąć do kwadratu, na którym znajduje się pompa.
Woda może przepływać między kwadratami, które stykają się bokami.
Wyznacz minimalną liczbę pomp koniecznych do osuszenia miasta.
Teren nie należący do miasta nie musi być osuszony.
Miasto nie musi tworzyć spójnego obszaru.
Failure
.pierwsze
, która dla danej liczby całkowitej \(n\) (\(n>1\)) wyznaczadomino : (α * α) list → (α * α) list
. Chcemy zwiedzić wszystkie te miejscowości, jednak nie w dowolnej kolejności.
Mamy daną listę ograniczeń postaci \([(i_1, j_1); \dots; (i_k,j_k)]\).
Ograniczenie \((i,j)\) oznacza, że miasto \(i\) musi być zwiedzone przed miastem \(j\).
Możesz założyć, że ograniczenia da się spełnić.
Na początku wyruszamy z miasta 1, a kończymy podróż w mieście \(n\).
Wyznacz minimalną drogę jaką trzeba przejechać, żeby zwiedzić wszystkie miasta.
Napisz procedurę \(\mathtt{energia}: \mathtt{int} \to \mathtt{int~array} \to \mathtt{int} \to \mathtt{int~array}\), która na podstawie liczby \(k\), tablicy \(t\) oraz energii \(e\) wyznaczy orbity, na których powinny znajdować się elektrony w atomie bajtonium tak, żeby ich łączna energia wynosiła \(e\). Wynikiem powinna być tablica \(k\) numerów powłok z elektronami, uporządkowana rosnąco. Jeżeli uzyskanie danej energii nie jest możliwe, wynikiem powinna być pusta tablica (\([||]\)).
Przykład: wynikiem energia 4 [|2; 8; 12; 12; 20|] 42
powinno być [|0; 1; 2; 4|]
lub [|0; 1; 3; 4|]
, natomiast energia 4 [|2; 8; 12; 12; 20|] 60 = [||]
.
Napisz procedurę klej : int list → int
, która na podstawie długości
kawałków obliczy minimalną ilość kleju (w ml) potrzebną do sklejenia wszystkich kawałków.
Napisz procedurę \(\mathtt{segment}: \mathtt{int~array} \to \mathtt{int}\), która dla danej tablicy \(t\) wyznaczy największy rząd występującego w niej segmentu Fibonacciego.
Jeżeli nie występuje w niej żaden taki segment, to poprawnym wynikiem jest zero.
Przykład: segment [| 1; 3; 2; 3; 4; 5; 3; 6|] = 7
. Segment Fibonacciego rzędu 7, to \([|3; 2; 3; 4; 5|]\) (\(Fib_7 = 13\)).
Po ulicach miasta kursuje autobus. Zaczyna on trasę przy skrzyżowaniu \((1, 1)\), a kończy przy skrzyżowaniu \((n, m)\).
Ponadto autobus może jechać ulicami tylko w kierunku wschodnim i/lub północnym.
Przy niektórych skrzyżowaniach znajdują się pasażerowie oczekujący na autobus.
Rozmieszczenie pasażerów jest dane w postaci prostokątnej tablicy a \(n \times m\) liczb całkowitych --
\(a.(i-1).(j-1)\) oznacza liczbę pasażerów czekających przy skrzyżowaniu \((i,j)\).
Napisz procedurę autobus
, która na podstawie tablicy a obliczy maksymalną liczbę pasażerów, których może zabrać autobus.
Zakładamy, że w autobusie zmieści się dowolna liczba pasażerów.
Napisz funkcję \(\mathtt{liczba\_prob} : \mathtt{int} \to \mathtt{int} \to \mathtt{int}\) taką, że \(\mathtt{liczba\_prob}\ n\ k\) zwróci najmniejszą (pesymistycznie) liczbę prób zrzucania jaj potrzebną do wyznaczenia \(p\) mając do dyspozycji \(k\) jaj.
Inaczej mówiąc, szukamy takiej strategii wyznaczenia \(p\), która w najgorszym przypadku będzie wymagać jak najmniejszej liczby zrzucań jajek.
Uwagi:
Na przykład: \(\mathtt{liczba\_prob}\ n\ 1 = n + 1\), \(~~\mathtt{liczba\_prob}\ 4\ 2 = 3\).
sklejanie : int list → int
obliczającą minimalną liczbę operacji ,,sklejania'', które należy wykonać, aby ciąg był rosnący.sklejanie [3; 5; 4; 2; 7] = 1
.
Równoważne zadanie pojawiło się na konkursie USACO Open Gold w 2009\,r. i zostało opisane w
Delcie.
type drzewo = Leaf | Node of int * drzewo * drzewo
Waga drzewa to suma wag rozgałęzień i siedzących na nich wróbli.
Drzewo nazwiemy zrównoważonym, jeśli w każdym rozgałęzieniu waga dwóch poddrzew będzie taka sama.
Rzucając celnie kamieniem w rozgałęzienie drzewa możemy przegonić wszystkie wróble z poddrzewa zaczepionego w tym rozgałęzieniu.
Napisz funkcję rownowaga : drzewo → bool
, która dla danego drzewa określa, czy da się tak rzucać kamieniami w drzewo,
aby stało się ono zrównoważone. Podaj złożoność czasową i pamięciową swojego rozwiązania.
Dla przykładu, aby zrównoważyć następujące drzewo:
Node (3, Node (5, Node (1, Leaf, Leaf), Node (7, Leaf, Leaf)), Node (2, Leaf, Leaf))
wystarczy raz rzucić kamieniem (w jego lewe poddrzewo).
moc [(2, 5, 10), (10, 12, 4), (-1, 2, 8), (6, 9, 10), (9, 15, 20), (4, 7, 8), (0, 12, 100), (8, 10, 4), (-2, 2, 6)] (1, 11) = 42
prostokąt : int array → int → int
, która dla zadanej tablicy \(a\) oraz liczby \(k\) Wynikiem procedury powinien być obwód tego prostokąta.
Podaj złożoność czasową i pamięciową swojego rozwiązania.
Prostokąt o dolnym lewym rogu \((x_1,y_1)\) i górnym prawym \((x_2,y_2)\) zawiera wszystkie elementy tablicy \(a.(i).(j)\) dla
\(x_1 \le i \le x_2\), \(y_1 \le j \le y_2\), oraz ma obwód \(2 \cdot (x_2 - x_1 + 1) + 2 \cdot (y_2 - y_1 + 1)\).
Przed wjazdem na most zostaną ustawione dwa ograniczenia: maksymalny dopuszczalny ciężar pojazdu\(C\) jaki może wjechać na most, oraz minimalna odległość\(D\) jaką należy zachować między pojazdami.
Jeśli dwie kolejne podpory znajdują się w odległości\(X\), to odcinki łączącego je mostu muszą mieć wytrzymałość przynajmniej \(\lceil \frac{X}{D}\rceil \cdot C\).
Ograniczenie\(C\) będzie równe minimalnej wytrzymałości całego mostu.
Twoim zadaniem jest wyznaczenie minimalnej możliwej wartości ograniczenia\(D\), jakie można uzyskać odpowiednio rozmieszczając podpory.
Napisz procedurę\(\mathtt{most}: \mathtt{int~array} \to \mathtt{int} \to \mathtt{int}\), która mając dane wytrzymałości odcinków mostu oraz liczbę podpór\(K\) wyznaczy minimalną możliwą wartość ograniczenia\(D\).
prostokat : int array array → int → (int * int) * (int * int)
, która dla tablicy \(a\) i Opis drzewa ma postać struktury listowej, w której każdy węzeł to lista jego synów.
Napisz procedurę koraliki
, która na podstawie opisu drzewa obliczy minimalny koszt koralików
potrzebnych do wykonania jego modelu.
Uwaga: Dwa kolory wystarczą do wykonania modelu, ale nie dają minimalnego kosztu.
Możesz założyć, że optymalna liczba kolorów nie przekracza \(\log_2 n\), gdzie \(n\) to liczba koralików.
Chcemy zoptymalizować liczbę i długość kawałków sznurka użytych do wykonania modelu drzewa:
Poniższe zadania rozwiązuje się (mniej lub bardziej) zachłannie.
Dla każdego z nich, oprócz programu, należy uzasadnić poprawność rozwiązania zachłannego.
nawiasy
, która obliczy minimalną liczbę nawiasów które należy obrócić, tak aby uzyskać poprawne wyrażenie nawiasowe.type nawias = Otwierający | Zamykający val nawiasy : nawias list → int
wakacje : int → int → int list → int
, która na podstawie liczb k i r, oraz Ciąg jednoelementowy i pusty są również naprzemienne.
Napisz procedurę $\mathtt{naprzemienny} : \mathtt{int~array} \to \mathtt{int}$, która mając dany ciąg liczb całkowitych
w postaci tablicy obliczy długość najdłuższego jego naprzemiennego podciągu.
Na przykład, \texttt{naprzemienny [|4;8;6;5;3;4;5;3;7;9;5;7|] = 8}.
Napisz procedurę \(\mathtt{ciag} : \mathtt{int} \to \mathtt{int~list}\),
która dla danej dodatniej liczby całkowitej $n$ wyznaczy najkrótszy taki
ciąg \((x_1, x_2, \dots, x_k)\), że \(x_k = n\).
harmonogram
która obliczy optymalną kolejność wykonywania zaległych zobowiązań.podzial : int → int list
, która dla danej nieujemnej liczby całkowitejpodzial 42 = [1; 2; 5; 13; 21]
.
ile [(1, 4); (7, 9); (-2, 3); (4, 9); (9, 12); (0, 5); (3, 7)] (-1, 11) = 4
Jasio bawi się jednym z samochodzików leżących na podłodze.
Oprócz Jasia w pokoju cały czas przebywa mama.
Gdy Jasio chce się bawić jakimś innym samochodzikiem i jeśli ten samochodzik jest na podłodze, to sięga po niego.
Jeśli jednak samochodzik znajduje się na półce, to musi mu go podać mama.
Mama podając Jasiowi jeden samochodzik, może przy okazji zabrać z podłogi dowolnie wybrany przez siebie
inny samochodzik i odłożyć go na półkę (tak, aby na podłodze nie brakło miejsca).
Mama bardzo dobrze zna swoje dziecko i wie dokładnie, którymi samochodzikami Jasio będzie chciał się bawić.
Dysponując tą wiedzą mama chce zminimalizować liczbę przypadków, gdy musi podawać Jasiowi samochodzik z półki.
W tym celu musi bardzo rozważnie odkładać samochodziki na półkę.
Napisz procedurę samochodziki
, która dla danej liczby k oraz listy samochodzików, którymi zechce się
bawić Jasio, obliczy minimalną liczbę razy, kiedy mama będzie musiała Jasiowi podać samochodzik.
ruchy : int array → (int * int * int) list
, która dla danej tablicy a wyznaczyRozwiązanie każdego z poniższych zadań wymaga użycia jednej z trzech technik:
back-trackingu, programowania dynamicznego lub zachłannego.
Pytanie której?
Napisz procedurę \(\mathtt{lamiglowka} : \mathtt{int~list} \to \mathtt{int}\), która dla danej listy \(l\) wyznaczy minimalną długość listy jaką można uzyskać.
Na przykład, \(\mathtt{lamiglowka}\ [4; 3; 4; 5; 12; 2; 3; 1; 6; 1] = 4\).
Dysponujesz \(k\) kotami (\(k \le n\)).
Twoim zadaniem jest takie rozmieszczenie kotów w korytarzu, żeby złapały jak najwięcej myszy.
Każdy kot może pilnować ustalonego przez Ciebie spójnego fragmentu korytarza (na przykład, może mieć założoną smycz odpowiedniej długości, przymocowaną do podłogi pośrodku pilnowanego fragmentu korytarza).
Fragmenty korytarza pilnowane przez różne koty nie mogą zachodzić na siebie (żeby koty się nie pobiły a smycze nie poplątały), choć mogą się stykać.
Niektóre fragmenty korytarza mogą pozostać niepilnowane przez żadnego kota.
Kot, który pilnuje fragmentu korytarza od \(i\) do \(j\) metrów od wejścia (dla \(i < j\)), na którym znajduje się \(s = a.(i) + a.(i+1) + \cdots + a.(j-1)\) myszy, złapie: \(\max(s - (j-i-1)^2, 0)\) myszy.
Na przykład, dla \(k=2\) oraz \(a = [|1; 5; 1; 4; 3; 2; 7; 0|]\) poprawnym wynikiem jest 14, jeden kot może pilnować fragmentu korytarza od 1 do 4 metrów od wejścia (łapiąc 6 z 10 myszy), a drugi może pilnować fragmentu korytarza od 4 do 7 metrów od wejścia (łapiąc 8 z 12 myszy).
Napisz procedurę \(\mathtt{myszy}: \mathtt{int} \to \mathtt{int~array} \to \mathtt{int}\), która dla danej liczby \(k \ge 0\) oraz tablicy \(a\), wyznaczy maksymalną liczbę myszy, jakie złapią koty.
Rozwiązanie tego zadania zostało omówione w Delcie
[15; 11; 7; 5; 3; 1]
.
Napisz procedurę \(\mathtt{ciag} : \mathtt{int} \to \mathtt{int~list}\), która dla danej dodatniej liczby całkowitej \(n\) wyznaczy najkrótszy taki ciąg \((x_1, x_2, \dots, x_k)\), że \(x_k = n\).
Na przykład \texttt{ciag 42} powinno zwrócić \([1; 2; 42]\) lub \([1; 21; 42]\).
Napisz procedurę ciąg : int → int list
, która dla danego \(n \ge 1\) znajdzie najkrótszy taki ciąg \(x_0, x_1, ..., x_k\), który spełnia powyższe warunki, oraz \(x_k = n\).
Wynikiem procedury powinna być lista \([x_0; ...; x_k]\).
Napisz procedurę \(\mathtt{ciag} : \mathtt{int} \to \mathtt{int~list}\), która dla danej dodatniej liczby całkowitej \(n\) wyznaczy najkrótszy taki ciąg \((x_1, x_2, \dots, x_k)\), że \(x_k = n\).
Możesz założyć, że dane są procedury:
rozklad : int * int → int list
, która dla danych liczb \(l\) i \(m\) wyznaczy szukany ciąg mianowników \([s_1;\dots;s_k]\).
Napisz procedurę \(\mathtt{rozklady} : \mathtt{int} \to \mathtt{int}\), która dla danej liczby \(x\)
policzy na ile różnych sposobów można przedstawić \(x\) jako sumę różnych (dodatnich) liczb Fibonacciego.
Na przykład \(\mathtt{rozklady}\ 42 = 6\).
podzial : int list → int → int list list
, która podzieli daną listę na \(k\) spójnych fragmentów Na przykład podzial [1; 4; 2; 2; 4; 1; 2; 4] 3 = [[1; 4; 2]; [2; 4]; [1; 2; 4]]
.
autobusy [|1; 0; 2; 1; 2; 0; 1; 2; 6; 0; 6; 0|] [|2; 6; 8; 11|] = 7}
.
koszt : int array → int
, która oblicza minimalny koszt posortowania tablicy \(p\).
type expr = NWD of expr * expr | NWW of expr * expr | Number of int
Drzewa takie reprezentują wyrażenia.
NWD
oznacza największy wspólny dzielnik, a NWW
najmniejszą wspólną wielokrotność dwóch podwyrażeń.
Argumentami Number
są liczby nieujemne.
\(\mathtt{Number}\ x\), dla \(x>0\) oznacza liczbę \(x\).
\(\mathtt{Number}\ 0\) oznacza miejsce, w które należy wstawić dodatnią liczbę.
Napisz procedurę \(\mathtt{wstaw}: \mathtt{expr} * \mathtt{int} \to \mathtt{int}\), która dla danego drzewa \(t\) i dodatniej liczby całkowitej \(n\) znajdzie taką najmniejszą dodatnią liczbę całkowitą \(x\), że gdy wstawimy \(\mathtt{Number}\ x\) w miejsce wszystkich wystąpień \(\mathtt{Number}\ 0\) w \(t\), to wartością wyrażenia będzie \(n\).
Jeżeli taka liczba \(x\) nie istnieje, to poprawnym wynikiem jest 0.
Na przykład, dla \(t = \mathtt{NWW(NWW(Number 2, Number 0), NWD(Number 0, Number 49))}\) i \(n = 42\), \(\mathtt{wstaw}\ t\ n = 21\).
Rozwiązania
type choinka = Koniuszek | Galaz of choinka | Rozgalezienie of choinka * choinka;;
opisujące kształt choinki.
Rozgalezienie, Galaz
i Koniuszek
) możemy umieszczać świeczki.Rozgalezienie, Galaz
i Koniuszek
) wieszamy bombki. Bombki należy zawiesić tak, aby choinka nie chwiała się, tzn. dla każdego rozgałęzienia łączny ciężar bombek
zawieszonych po lewej i po prawej stronie musi być taki sam.
Pytanie czy jest to możliwe, a jeżeli tak, to na ile sposobów?
Napisz procedurę, która dla danej choinki obliczy na ile sposobów można powiesić na niej bombki.
szukaj : char array → char array → int
, która znajduje najdłuższyokresy: int list → int list
, której wynikiem dla danej listy \([x_1; x_2; \dots; x_n]\) Zauważmy, że każdy ciąg ma okres całkowity, co najwyżej jest to \(k=n\).
Na przykład, okresem całkowitym ciągu \([1;3;2;1;1;3;2;1;1;3;2;1]\) jest 4, a okresem całkowitym ciągu \([1;3;2;1;1]\) jest 5.
Napisz procedurę okres : int array → int
, która dla danego ciągu wyznaczy jego okres całkowity.
Napisz procedurę, która dla danego (w postaci listy) napisu obliczy listę długości maksymalnych
okresów kolejnych jego prefiksów.
Napisz procedurę \(\mathtt{minrot}: \mathtt{char~array} \to \mathtt{int}\),
która dla danej tablicy znaków \(a\) zwróci taką liczbę \(i\), że rotacja tablicy \(a\) o \(i\) pozycji jest najmniejsza w porządku leksykograficznym,
spośród wszystkich jej rotacji cyklicznych.
podsłowo : char array → (int * int)
,Dla pustej tablicy poprawnym wynikiem jest (0,0).