1. domača naloga#
Ogrevanje#
Collatzovo zaporedje#
Collatzovo zaporedje se začne s pozitivnim naravnim številom \(a_0\) ter nadaljuje kot:
Sestavite funkcijo collatz : int -> int list
, ki sprejme začetni člen zaporedja in vrne seznam vseh členov, dokler zaporedje ne doseže \(1\).
let primer_ogrevanje_1 = collatz 1024
val primer_ogrevanje_1 : int list =
[1024; 512; 256; 128; 64; 32; 16; 8; 4; 2; 1]
let primer_ogrevanje_2 = collatz 27
val primer_ogrevanje_2 : int list =
[27; 82; 41; 124; 62; 31; 94; 47; 142; 71; 214; 107; 322; 161; 484; 242;
121; 364; 182; 91; 274; 137; 412; 206; 103; 310; 155; 466; 233; 700; 350;
175; 526; 263; 790; 395; 1186; 593; 1780; 890; 445; 1336; 668; 334; 167;
502; 251; 754; 377; 1132; 566; 283; 850; 425; 1276; 638; 319; 958; 479;
1438; 719; 2158; 1079; 3238; 1619; 4858; 2429; 7288; 3644; 1822; 911;
2734; 1367; 4102; 2051; 6154; 3077; 9232; 4616; 2308; 1154; 577; 1732;
866; 433; 1300; 650; 325; 976; 488; 244; 122; 61; 184; 92; 46; 23; 70; 35;
106; 53; 160; 80; 40; 20; 10; 5; 16; 8; 4; 2; 1]
Fiksne točke#
Sestavite funkcijo fiksne_tocke : ('a -> 'a) -> 'a list -> 'a list
, ki za dano funkcijo in seznam vrne podseznam vseh elementov, ki so fiksne točke.
let primer_ogrevanje_3 = fiksne_tocke (fun x -> x * x) [0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
val primer_ogrevanje_3 : int list = [0; 1]
let primer_ogrevanje_4 = fiksne_tocke List.rev [[3]; [1; 4; 1]; [5; 9; 2; 6]; [5; 3; 5]; []; [8; 9; 7; 9; 3; 2; 3]]
val primer_ogrevanje_4 : int list list = [[3]; [1; 4; 1]; [5; 3; 5]; []]
Združevanje z ločilom#
Napišite funkcijo sep_concat : 'a -> 'a list list -> 'a list
, ki združi seznam seznamov, pri čemer med elemente različnih seznamov ter na začetek in konec vstavi dano ločilo.
let primer_ogrevanje_5 = sep_concat 42 [[1; 2; 3]; [4; 5]; []; [6]]
val primer_ogrevanje_5 : int list = [42; 1; 2; 3; 42; 4; 5; 42; 42; 6; 42]
let primer_ogrevanje_6 = sep_concat 42 []
val primer_ogrevanje_6 : int list = [42]
Razbitje seznama#
Napišite funkcijo partition : int -> 'a list -> 'a list
, ki sprejme pozitivno naravno število \(k\) in seznam \([a_0, \dots, a_n]\) ter ga razdeli na zaporedne podsezname \([a_0, \dots, a_{k - 1}], [a_k, \dots, a_{2 k - 1}], \dots\), pri čemer je zadnji podseznam lahko tudi krajši.
let primer_ogrevanje_7 = partition 3 [1; 2; 3; 4; 5; 6; 7; 8; 9]
val primer_ogrevanje_7 : int list list = [[1; 2; 3]; [4; 5; 6]; [7; 8; 9]]
let primer_ogrevanje_8 = partition 3 [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
val primer_ogrevanje_8 : int list list =
[[1; 2; 3]; [4; 5; 6]; [7; 8; 9]; [10]]
Izomorfizmi množic#
Na predavanjih smo videli, da funkciji curry : ('a * 'b -> 'c) -> ('a -> ('b -> 'c))
in uncurry : ('a -> ('b -> 'c)) -> ('a * 'b -> 'c)
predstavljata izomorfizem množic \(C^{A \times B} \cong (C^B)^A\), če kartezični produkt predstavimo s produktnim, eksponent pa s funkcijskim tipom.
Podobno velja tudi za ostale znane izomorfizme, če disjunktno unijo
$\(A + B = \{ \mathrm{in}_1(a) \mid a \in A \} \cup \{ \mathrm{in}_2(b) \mid b \in B \}\)$
predstavimo s tipom ('a, 'b) sum
, definiranim z:
type ('a, 'b) sum = In1 of 'a | In2 of 'b
type ('a, 'b) sum = In1 of 'a | In2 of 'b
Napišite pare funkcij phi1
& psi1
, …, phi7
& psi7
, ki predstavljajo spodnje izomorfizme množic. Tega, da so si funkcije inverzne, ni treba dokazovati.
\(A \times B \cong B \times A\)#
\(A + B \cong B + A\)#
\(A \times (B \times C) \cong (A \times B) \times C\)#
\(A + (B + C) \cong (A + B) + C\)#
\(A \times (B + C) \cong (A \times B) + (A \times C)\)#
\(A^{B + C} \cong A^B \times A^C\)#
\((A \times B)^C \cong A^C \times B^C\)#
Permutacije#
Permutacije so preureditve elementov \(\{0, 1, \dots, n-1\}\), torej bijektivne preslikave
V nalogi bomo permutacije predstavili s seznamom števil, v katerem je na \(i\)-tem mestu seznama zapisana slika elementa \(i\). Na primer, permutaciji \(0 \, 1 \, 2 \, 3 \, 4 \, 5 \choose 5 \, 3 \, 2 \, 1 \, 4 \, 0\) in \(0 \, 1 \, 2 \, 3 \, 4 \, 5 \, 6 \, 7 \, 8 \, 9 \choose 3 \, 9 \, 1 \, 7 \, 5 \, 4 \, 6 \, 8 \, 2 \, 0\) bi zapisali s seznamoma:
let permutacija_1 = [5; 3; 2; 1; 4; 0]
let permutacija_2 = [3; 9; 1; 7; 5; 4; 6; 8; 2; 0]
val permutacija_1 : int list = [5; 3; 2; 1; 4; 0]
val permutacija_2 : int list = [3; 9; 1; 7; 5; 4; 6; 8; 2; 0]
Kompozitum#
Napišite funkcijo kompozitum : int list -> int list -> int list
, ki sprejme dve permutaciji in vrne njun kompozitum. Za permutaciji \(p\) in \(q\), je njun kompozitum funkcija
Predpostavite lahko, da sta seznama enakih dolžin.
let primer_permutacije_1 = kompozitum permutacija_1 permutacija_1
val primer_permutacije_1 : int list = [0; 1; 2; 3; 4; 5]
let primer_permutacije_2 = kompozitum permutacija_2 permutacija_2
val primer_permutacije_2 : int list = [7; 0; 9; 8; 4; 5; 6; 2; 1; 3]
Inverz#
Napiši funkcijo inverz : int list -> int list
, ki vrne inverz dane permutacije \(p\), torej tako permutacijo \(p^{-1}\), da velja
kjer je \(\mathrm{id}\) indentiteta.
let primer_permutacije_3 = inverz permutacija_1
val primer_permutacije_3 : int list = [5; 3; 2; 1; 4; 0]
let primer_permutacije_4 = inverz permutacija_2
val primer_permutacije_4 : int list = [9; 2; 8; 0; 5; 4; 6; 3; 7; 1]
let primer_permutacije_5 = kompozitum permutacija_2 (inverz permutacija_2)
val primer_permutacije_5 : int list = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]
Razcep na cikle#
Napišite funkcijo cikli : int list -> int list list
, ki za dano permutacijo vrne seznam ciklov, ki to permutacijo sestavljajo. Vsak element \(\{0, 1, \dots, n-1\}\) naj se pojavi v natanko enem ciklu.
let primer_permutacije_6 = cikli permutacija_1
val primer_permutacije_6 : int list list = [[0; 5]; [1; 3]; [2]; [4]]
let primer_permutacije_7 = cikli permutacija_2
val primer_permutacije_7 : int list list =
[[0; 3; 7; 8; 2; 1; 9]; [4; 5]; [6]]
let primer_permutacije_8 = cikli (inverz permutacija_2)
val primer_permutacije_8 : int list list =
[[0; 9; 1; 2; 8; 7; 3]; [4; 5]; [6]]
Transpozicije permutacije#
Vsako permutacijo lahko zapišemo kot produkt transpozicij, torej menjav dveh elementov. Na primer, permutacijo \(0 \, 1 \, 2 \, 3 \choose 1 \, 0 \, 3 \, 2\) dobimo kot produkt transpozicij \((0, 1) \circ (2, 3)\).
Napišite funkcijo iz_transpozicij : int -> (int * int) list -> int list
, ki sprejme dolžino permutacije in seznam transpozicij ter vrne permutacijo, ki jim ustreza.
let primer_permutacije_9 = iz_transpozicij 4 [(0, 1); (2, 3)]
val primer_permutacije_9 : int list = [1; 0; 3; 2]
Napišite funkcijo v_transpozicije : int list -> (int * int) list
, ki zapiše permutacijo kot produkt transpozicij, torej menjav dveh elementov. Možnih produktov je več, veljati mora le, da je kompozicija dobljenih ciklov enaka prvotni permutaciji.
Namig: Pomagate si lahko z lastnostjo, da poljubni cikel razpade na transpozicije po naslednji formuli
let primer_permutacije_10 = v_transpozicije permutacija_1
val primer_permutacije_10 : (int * int) list = [(0, 5); (1, 3)]
let primer_permutacije_11 = v_transpozicije permutacija_2
val primer_permutacije_11 : (int * int) list =
[(0, 9); (0, 1); (0, 2); (0, 8); (0, 7); (0, 3); (4, 5)]
Sudoku#
Sudoku je igra, v kateri mrežo \(9 \times 9\) dopolnimo s števili od \(1\) do \(9\), tako da se nobeno število v nobeni vrstici, stolpcu ali eni od devetih škatel velikosti \(3 \times 3\) ne ponovi. Primer začetne postavitve in ustrezne rešitve je:
+-------+-------+-------+ +-------+-------+-------+
| 5 4 . | . 7 . | . . . | | 5 4 3 | 6 7 8 | 9 1 2 |
| 6 . . | 1 9 5 | . . . | | 6 7 2 | 1 9 5 | 3 4 8 |
| . 9 8 | . . . | . 6 . | | 1 9 8 | 3 4 2 | 5 6 7 |
+-------+-------+-------+ +-------+-------+-------+
| 8 . . | . 6 . | . . 3 | | 8 1 9 | 7 6 4 | 2 5 3 |
| 4 . . | 8 . 3 | . . 1 | | 4 2 6 | 8 5 3 | 7 9 1 |
| 7 . . | . 2 . | . . 6 | | 7 3 5 | 9 2 1 | 4 8 6 |
+-------+-------+-------+ +-------+-------+-------+
| . 6 . | . . 7 | 8 . . | | 9 6 1 | 5 3 7 | 8 2 4 |
| . . . | 4 1 9 | . . 5 | | 2 8 7 | 4 1 9 | 6 3 5 |
| . . . | . 8 . | . 7 9 | | 3 5 4 | 2 8 6 | 1 7 9 |
+-------+-------+-------+ +-------+-------+-------+
Delno izpolnjen sudoku bomo predstavili s tabelo tabel tipa int option array array
, kjer bomo prazna mesta označili z None
, rešen sudoku pa s tabelo tabel običajnih števil.
type mreza = int option array array
type resitev = int array array
type mreza = int option array array
type resitev = int array array
Na primer, zgornjo mrežo in rešitev bi predstavili s seznamoma:
let primer_mreze : mreza = [|
[|Some 5; Some 4; None; None; Some 7; None; None; None; None|];
[|Some 6; None; None; Some 1; Some 9; Some 5; None; None; None|];
[|None; Some 9; Some 8; None; None; None; None; Some 6; None|];
[|Some 8; None; None; None; Some 6; None; None; None; Some 3|];
[|Some 4; None; None; Some 8; None; Some 3; None; None; Some 1|];
[|Some 7; None; None; None; Some 2; None; None; None; Some 6|];
[|None; Some 6; None; None; None; Some 7; Some 8; None; None|];
[|None; None; None; Some 4; Some 1; Some 9; None; None; Some 5|];
[|None; None; None; None; Some 8; None; None; Some 7; Some 9|]
|]
let primer_resitve : resitev = [|
[|5; 4; 3; 6; 7; 8; 9; 1; 2|];
[|6; 7; 2; 1; 9; 5; 3; 4; 8|];
[|1; 9; 8; 3; 4; 2; 5; 6; 7|];
[|8; 1; 9; 7; 6; 4; 2; 5; 3|];
[|4; 2; 6; 8; 5; 3; 7; 9; 1|];
[|7; 3; 5; 9; 2; 1; 4; 8; 6|];
[|9; 6; 1; 5; 3; 7; 8; 2; 4|];
[|2; 8; 7; 4; 1; 9; 6; 3; 5|];
[|3; 5; 4; 2; 8; 6; 1; 7; 9|];
|]
val primer_mreze : mreza =
[|[|Some 5; Some 4; None; None; Some 7; None; None; None; None|];
[|Some 6; None; None; Some 1; Some 9; Some 5; None; None; None|];
[|None; Some 9; Some 8; None; None; None; None; Some 6; None|];
[|Some 8; None; None; None; Some 6; None; None; None; Some 3|];
[|Some 4; None; None; Some 8; None; Some 3; None; None; Some 1|];
[|Some 7; None; None; None; Some 2; None; None; None; Some 6|];
[|None; Some 6; None; None; None; Some 7; Some 8; None; None|];
[|None; None; None; Some 4; Some 1; Some 9; None; None; Some 5|];
[|None; None; None; None; Some 8; None; None; Some 7; Some 9|]|]
val primer_resitve : resitev =
[|[|5; 4; 3; 6; 7; 8; 9; 1; 2|]; [|6; 7; 2; 1; 9; 5; 3; 4; 8|];
[|1; 9; 8; 3; 4; 2; 5; 6; 7|]; [|8; 1; 9; 7; 6; 4; 2; 5; 3|];
[|4; 2; 6; 8; 5; 3; 7; 9; 1|]; [|7; 3; 5; 9; 2; 1; 4; 8; 6|];
[|9; 6; 1; 5; 3; 7; 8; 2; 4|]; [|2; 8; 7; 4; 1; 9; 6; 3; 5|];
[|3; 5; 4; 2; 8; 6; 1; 7; 9|]|]
Dopolnitev mreže#
Napišite funkcijo dodaj : int -> int -> int -> mreza -> mreza
tako da dodaj i j n m
vrne mrežo, ki je povsod enaka mreži m
, le na mestu v vrstici i
in stolpcu j
ima zapisano število n
.
Pozor: OCaml dopušča spreminjanje tabel (o tem se bomo učili kasneje). Vaša funkcija naj te možnosti ne uporablja, temveč naj sestavi in vrne novo tabelo.
let primer_sudoku_1 = primer_mreze |> dodaj 0 8 2
val primer_sudoku_1 : mreza =
[|[|Some 5; Some 4; None; None; Some 7; None; None; None; Some 2|];
[|Some 6; None; None; Some 1; Some 9; Some 5; None; None; None|];
[|None; Some 9; Some 8; None; None; None; None; Some 6; None|];
[|Some 8; None; None; None; Some 6; None; None; None; Some 3|];
[|Some 4; None; None; Some 8; None; Some 3; None; None; Some 1|];
[|Some 7; None; None; None; Some 2; None; None; None; Some 6|];
[|None; Some 6; None; None; None; Some 7; Some 8; None; None|];
[|None; None; None; Some 4; Some 1; Some 9; None; None; Some 5|];
[|None; None; None; None; Some 8; None; None; Some 7; Some 9|]|]
Izpiši mrežo#
Sestavite funkciji izpis_mreze : mreza -> string
in izpis_resitve : resitev -> string
, ki sprejmeta mrežo oziroma rešitev in vrneta niz, ki predstavlja izpis v zgornji obliki.
let primer_sudoku_2 = primer_mreze |> izpis_mreze |> print_endline
+-------+-------+-------+
| 5 4 . | . 7 . | . . . |
| 6 . . | 1 9 5 | . . . |
| . 9 8 | . . . | . 6 . |
+-------+-------+-------+
| 8 . . | . 6 . | . . 3 |
| 4 . . | 8 . 3 | . . 1 |
| 7 . . | . 2 . | . . 6 |
+-------+-------+-------+
| . 6 . | . . 7 | 8 . . |
| . . . | 4 1 9 | . . 5 |
| . . . | . 8 . | . 7 9 |
+-------+-------+-------+
val primer_sudoku_2 : unit = ()
let primer_sudoku_3 = izpis_resitve primer_resitve |> print_endline
+-------+-------+-------+
| 5 4 3 | 6 7 8 | 9 1 2 |
| 6 7 2 | 1 9 5 | 3 4 8 |
| 1 9 8 | 3 4 2 | 5 6 7 |
+-------+-------+-------+
| 8 1 9 | 7 6 4 | 2 5 3 |
| 4 2 6 | 8 5 3 | 7 9 1 |
| 7 3 5 | 9 2 1 | 4 8 6 |
+-------+-------+-------+
| 9 6 1 | 5 3 7 | 8 2 4 |
| 2 8 7 | 4 1 9 | 6 3 5 |
| 3 5 4 | 2 8 6 | 1 7 9 |
+-------+-------+-------+
val primer_sudoku_3 : unit = ()
Preveri, ali rešitev ustreza mreži#
Napišite funkcijo ustreza : mreza -> resitev -> bool
, ki preveri, ali rešitev ustreza dani mreži. Rešitev ustreza mreži, če se na vseh mestih, kjer je v mreži podana številka, v rešitvi nahaja enaka številka.
let primer_sudoku_4 = ustreza primer_mreze primer_resitve
val primer_sudoku_4 : bool = true
Kandidati za dano prazno mesto#
Napišite funkcije ni_v_vrstici
, ni_v_stolpcu
in ni_v_skatli
, vse tipa mreza * int -> int -> bool
, ki preverijo, ali se v določeni vrstici, stolpcu oziroma škatli mreže ne nahaja dano število. Vrstice, stolpci in škatle so indeksirani kot:
0 1 2 3 4 5 6 7 8
+-------+-------+-------+
0 | | | |
1 | 0 | 1 | 2 |
2 | | | |
+-------+-------+-------+
3 | | | |
4 | 3 | 4 | 5 |
5 | | | |
+-------+-------+-------+
6 | | | |
7 | 6 | 7 | 8 |
8 | | | |
+-------+-------+-------+
let primer_sudoku_5 = ni_v_vrstici (primer_mreze, 0) 1
val primer_sudoku_5 : bool = true
let primer_sudoku_6 = ni_v_vrstici (primer_mreze, 1) 1
val primer_sudoku_6 : bool = false
Napišite funkcijo kandidati : mreza -> int -> int -> int list option
, ki sprejme mrežo in indeksa vrstice in stolpca praznega mesta ter vrne seznam vseh številk, ki se lahko pojavijo na tem mestu. Če je polje že izpolnjeno, naj funkcija vrne None
.
let primer_sudoku_7 = kandidati primer_mreze 0 2
val primer_sudoku_7 : int list option = Some [1; 2; 3]
let primer_sudoku_8 = kandidati primer_mreze 0 0
val primer_sudoku_8 : int list option = None
Iskanje rešitve#
Napišite funkcijo resi : mreza -> resitev option
, ki izpolni mrežo sudokuja. Če je dana mreža rešljiva, mora funkcija najti rešitev, ki ustreza začetni mreži in jo vrniti v obliki Some resitev
, sicer naj vrne None
. Predpostavite lahko, da je rešitev enolična, zato lahko funkcija vrne prvo, ki jo najde.
Namig: Poiščite celico mreže z najmanj kandidati in rekurzivno preizkusite vse možnosti.
let primer_sudoku_9 = resi primer_mreze
val primer_sudoku_9 : resitev option =
Some
[|[|5; 4; 3; 6; 7; 8; 9; 1; 2|]; [|6; 7; 2; 1; 9; 5; 3; 4; 8|];
[|1; 9; 8; 3; 4; 2; 5; 6; 7|]; [|8; 1; 9; 7; 6; 4; 2; 5; 3|];
[|4; 2; 6; 8; 5; 3; 7; 9; 1|]; [|7; 3; 5; 9; 2; 1; 4; 8; 6|];
[|9; 6; 1; 5; 3; 7; 8; 2; 4|]; [|2; 8; 7; 4; 1; 9; 6; 3; 5|];
[|3; 5; 4; 2; 8; 6; 1; 7; 9|]|]