Programowanie – czerwiec 2004 Wersja A
Transkrypt
Programowanie – czerwiec 2004 Wersja A
Programowanie – czerwiec 2004
Wersja A
Za cały egzamin będzie można dostać 100 punktów (nie licząc punktów bonusowych). Progi są następujące: 34 punkty
daje ocenę dostateczną, 47 dostateczną z plusem, 60 dobrą, 73 dobrą z plusem, 86 bardzo dobrą.
W jednym zadaniu pojawia się sformułowanie dowolny język programowania. Oznacza ono jeden z języków:
Pascal, C, C++, Python, Haskell, SML lub Prolog. We wszystkich zadaniach programistycznych liczy się również
elegancja rozwiązania.
Zadanie 1. (18p)
Gramatyka G1 nad alfabetem {a, b}, określona jest przez przez zbiór produkcji P 1
P1 = {S → aSb, S → ε, S → SS}
Gramatyka G2 nad alfabetem {a, b}, określona jest przez przez zbiór produkcji P 2
P2 = {S → aSa, S → bSb S → ε, S → SS}
a) Napisz w języku C funkcję bool f1(char *s), która zwraca prawdę, jeżeli słowo s (o którym wiemy, że składa się
jedynie z literek a oraz b) należy do języka L(G1 ) ∩ (a+ b)∗ . (6p)
b) Napisz w języku C funkcję bool f2(char *s), która zwraca prawdę, jeżeli słowo s (o którym wiemy, że składa się
jedynie z literek a oraz b) należy do języka L(G2 ) ∩ a∗ b∗ c∗ . (6p)
c) Przedstaw wyrażenie regularne opisujące język L(G 1 ) ∩ L(G2 ) ∩ (aabb)∗ . Uzasadnij odpowiedź. (6p)
Zadanie 2. (10p) Zamień poniższe programy na ich odpowiedniki, w których nie ma instrukcji goto, a jedynymi
strukturami sterującymi są pętla while i instrukcja if. Możesz wprowadzać nowe zmienne, przypisywać im wartości i
sprawdzać je.
Występujące w programach warunki nie wywołują efektów ubocznych.
a) (5p)
L1: C1
if (b1) goto L2
C2
L2: if (b2) goto L1
b) (5p)
do {
L1: C1
if (b1) break;
} while (b2)
C2
if (b3) goto L1
Zadanie 3. (10p) Poniższe fragmenty programów w języku C nie robią tego, co mają robić. Dla każdego z nich
powiedz, gdzie jest problem i napisz program poprawnie (zwróć również uwagę na styl):
a) Program liczy liczbę wystąpień najczęściej występującej liczby w posortowanej tablicy T. Dla tablicy o zawartości
{0,0,0,0,1,1,1,2,2,3} powinien wypisać 4, bo najczęściej występująca liczba (czyli 0) ma właśnie tyle wystąpień
licznik = 0
for (i=0;i<N;i++) {
if (T[i-1] == T[i]) licznik++;
else {
if (licznik > max) max = licznik;
}
}
printf("%d",licznik);
b) Program sprawdza, czy napis s1 jest przed napisem s2 w porządku leksykograficznym i zwraca 1 jeżeli tak, 0 jeżeli
te napisy są równe, -1 jeżeli to drugi napis poprzedza ten pierwszy.
int strcmp(char *s1, char *s2) {
int l = strlen(s1);
int i;
for (i=0; i<l; i++) {
if (s1[i] < s2[i]) return -1;
if (s1[i] > s2[i]) return 1;
}
return 0;
}
Zadanie 4. (18p) W zadaniu tym używamy składni Haskella. Rozwiązanie możesz przedstawić w Haskelu albo w
SML-u. Zdefiniujemy typ drzewo:
data Tree a = Lf a | Br (Tree a) (Tree a)
(jak widać wartości są przechowywane w liściach, a najmniejsze drzewo ma 1 element). Wyrażenie arytmetyczne zbudowane z liczb oraz znaku + możemy reprezentować za pomocą takiego drzewa, przykładowo 1+(2+3), w tej reprezentacji
ma postać Br (Lf 1) (Br (Lf 2) (Lf 3)).
a) Napisz ogonową funkcję sum, która bierze listę i zwraca sumę jej elementów. W funkcji tej nie wolno wywoływać
innych funkcji. (3p)
b) Napisz funkcję val, która bierze drzewo, traktuje je jak wyrażenie w sposób opisany powyżej i zwraca jego wartość.
(3p)
c) Funkcja tolist zdefiniowana jest następująco:
tolist (Lf x) = [x]
tolist (Br t1 t2) = (tolist t1) ++ (tolist t2)
Sformuuj dla typu tree zasadę indukcji (2p). Następnie z jej pomocą udowodnij (10p), że dla każdego drzewa T
przechowującego liczby, mamy
sum (tolist T) = val T
Zadanie 5. (31p) W zadaniu tym będziemy używać notacji listowej pochodzącej z Haskela, Pythona i Prologa. Jeżeli
używasz Prologa, to zamiast funkcji musisz pisać odpowiednie relacje. Wszystkie programy w tym zadaniu możesz
napisać używając dowolnego języka (ale jednego dla całego zadania, oczywiście jeżeli w języku nie ma list, to musisz je
samodzielnie zaimplementować). Możesz korzystać ze standardowych bibliotek z wybranego języka.
Zajmiemy się zadaniem rozmieszczenia N hetmanów na szachownicy N × N , w ten sposób, żeby wzajemnie się nie
atakowały (hetman atakuje innego, jeżeli znajdują się na tym samym wierszu, w tej samej kolumnie lub na tej samej
linii diagonalnej). Rozwiązanie możemy kodować w sposób następujący: ponieważ w każdej kolumnie powinien znaleźć
się dokładnie jeden hetman (dlaczego, (1p)), wystarczy, że zapamiętamy jego pozycję (liczbę od 0 do N − 1). Lista
takich liczb koduje jednoznacznie rozwiązanie.
Przykładowo dla N = 4, mamy jedno z rozwiązań wygląda następująco:
.*..
...*
*...
..*.
== [2,0,3,1]
Zaprogramuj funkcje (w przypadku, gdy zauważysz jakieś konflikty nazw masz prawo do nazwy swojej funkcji dopisać
cyfrę 0):
1. insert(e,K,L) wstawiającą element e do listy L na pozycję K , tak aby: insert(13,0,[1,2,3,4]) = [13,1,2,3,4],
insert(13,2,[1,2,3,4]) = [1,2,13,3,4]. (2p)
2. range(K) = [0,1,2,3,...,K-1], (2p)
3. allInserts(E,L) zwracającą listę list, które wszystkie powstały w wyniku wstawienia elementu E w różne miejsca,
allInserts(0,[1,2,3]) = [ [0,1,2,3], [1,0,2,3], [1,2,0,3], [1,2,3,0] ], (4p) (w tym zadaniu można
uzyskać 2p premii za użycie funkcjonału map)
2
4. toflat(L) spłaszczającą listę list, czyli toflat([ [1,2],[3,4],[5,6,7] ]) = [1,2,3,4,5,6,7]., (3p)
5. allPerms(L) zwracającą listę wszystkich permutacji listy L (w dowolnej kolejności), przykładowo allPerms([1,2,3])=[
[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,2,1], [3,1,2] ].,(6p)
6. attack(K,L), zwracającą wartość logiczną, mówiącą o tym, że hetman na K-tej pozycji, na prawo od którego stoją
hetmany na pozycjach zapisanych w liście L, atakuje któregoś z tych hetmanów po linii diagonalnej. (7p)
7. safe(L), zwracająca wartość logiczną, mówiącą o tym, że lista L, będąca permutacją liczb 0,1,...,N-1 koduje
rozwiązanie zagadki N hetmanów. (3p)
8. allSolutions(N) zwraca wszystkie rozmieszczenia N hetmanów, będące rozwiązaniem zagadki. (4p)
Zadanie 6. 10 Odpowiedz na poniższe pytania. Proszę o odpowiedź na każde z pytań, przy czym odpowiedź należy
wybrać ze zbioru: T,N,?. Odpowiedź ? warta jest zawsze 0 punktów, odpowiedi T oraz N są warte -2 lub 2, w zależności
od tego, czy są poprawne.
1. Ponieważ Haskell jest językiem leniwym, to programy w nim napisane nigdy się nie zapętlają. Prawda?
2. Czy 1+[2,3] jest poprawnym termem w Prologu?
3. Ponieważ napisy w Pythonie są typami niezmiennymi, program
x = "ala ma kota"
x = "nieprawda, bo psa"
spowoduje błąd czasu wykonania.
4. W jednej funkcji w C++ zmienna i może być zdefiniowana kilkakrotnie z różnymi (być może) typami.
5. W Haskellu zakłada się, że wartości każdego typu można porównać.
3