Papugi (Parrots) Bajtazarka interesuje się ornitologią. Od kiedy przeczytała o protokole IP over Avian Carriers (IPoAC, protokół transferu pakietów IP przez gołębie pocztowe), spędza sporo czasu, ucząc hordę inteligentnych papug przenoszenia wiadomości na długich dystansach. Marzeniem Bajtazarki jest użycie papug do wysłania wiadomości M do odległego kraju. Wiadomość M jest ciągiem N liczb całkowitych (niekoniecznie różnych od siebie), z przedziału [0, 255]. Bajtazarka hoduje K specjalnie przeszkolonych papug. Wszystkie papugi są identyczne i nawet Bajtazarka nie potrafi ich rozróżnić. Każdy ptak potrafi zapamiętać liczbę z przedziału [0, R]. Pewnego razu, Bajtazarka spróbowała przesłać wiadomość. W tym celu wypuszczała papugi z klatki jedna za drugą. Zanim każdy ptak wzbił się w powietrze, Bajtazarka uczyła go kolejnej liczby z ciągu. Niestety, pomysł nie wypalił. Wprawdzie ptaki dotarły do celu, jednak w innej kolejności niż powinny. To pozwoliło Bajtazarce odtworzyć wszystkie wysłane liczby, jednak nie potrafiła odtworzyć ich prawidłowej kolejności. Aby spełnić swe marzenie, Bajtazarka potrzebuje lepszej metody i dlatego prosi Cię o pomoc. Dla podanej wiadomości M, chce ona wypuszczać ptaki jeden po drugim, tak jak poprzednio. Poprosiła Cię o napisanie programu, który wykona dwie operacje: Po pierwsze, powinien umożliwić wczytanie wiadomości M i przetworzenie jej w ciąg co najwyżej K liczb całkowitych z przedziału [0, R]. Bajtarka nauczy papugi kolejnych liczb z wyznaczonego ciągu. Po drugie, program powinien umożliwić wczytanie listy liczb całkowitych z przedziału [0, R], która opisuje liczby dostarczone do celu przez papugi. Z podanej listy powinien odtworzyć oryginalną wiadomość M. Możesz założyć, że wszystkie papugi zawsze docierają do celu i że każda z nich poprawnie pamięta podany jej numer. Bajtazarka przypomina raz jeszcze, że papugi mogą przylecieć w dowolnej kolejności. Zwróć uwagę, że Bajtazarka dysponuje K papugami, więc wyznaczony ciąg liczb całkowitych z przedziału [0, R] musi składać się z co najwyżej K liczb. Zadanie Napisz dwie osobne procedury. Jedną dla nadawcy (encoder), zaś drugą dla odbiorcy (decoder). Cały proces został pokazany na poniższym obrazku (shuffle oznacza pewne przetasowanie kolejności ptaków). Tłumaczenie rysunku: oryginalna wiadomość M, zakodowana wiadomość E, przetasowana wiadomość X, wiadomość wyjściowa (powinna być równa M). Page 1 of 5
Procedury, które należy napisać, to: Procedura encode(n,m). Jej parametry są następujące: N długość wiadomości. M jednowymiarowa tablica N liczb całkowitych, które opisują wiadomość. Możesz założyć, że dla 0 i < N zachodzi 0 M[i] 255. Ta procedura powinna zakodować wiadomość M do ciągu liczb całkowitych z przedziału [0,R], który należy nadać. Procedura encode podaje wyznaczony ciąg przez wywołanie send(a) dla każdej liczby całkowitej a, którą trzeba wysłać przy pomocy papug. Procedura decode(n,l,x). Jej parametry są następujące: N długość oryginalnej wiadomości. L długość otrzymanej wiadomości, tj. liczba wysłanych ptaków. X jednowymiarowa tablica L liczb całkowitych, które opisują otrzymane liczby. Liczby X[i] (0 i < L) to dokładnie te same liczby, które wyznaczyła Twoja implementacja procedury encode, jednak być może w innej kolejności. Ta procedura powinna odtworzyć oryginalną wiadomość. Aby podać wynik, powinna ona wywołać output(b) dla kolejnych liczb b tworzących odkodowaną wiadomość we właściwej kolejności. Zwróć uwagę, że R i K nie są podane jako parametry, lecz są ustalone w poszczególnych podzadaniach. Aby poprawnie rozwiązać dane podzadanie, procedury muszą spełnić poniższe warunki: Wszystkie liczby wyznaczone przez procedurę encode muszą mieścić się w zakresie określonym w podzadaniu. Liczba wywołań procedury send w procedurze encode nie może przekroczyć ograniczenia K określonego w podzadaniu. Procedura decode musi poprawnie odtworzyć oryginalną wiadomość M oraz wywołać output(b) dokładnie N razy, dla b równego kolejno M[0], M[1],..., M[N-1]. W ostatnim podzadaniu, Twój wynik zależy od ilorazu długości zakodowanej wiadomości oraz oryginalnej wiadomości. Przykład Rozważmy przykład, w którym N = 3 oraz M = 10 30 20 Procedura encode(n,m), przy użyciu sobie znanego sposobu, może zakodować wiadomość do ciągu (7, 3, 2, 70, 15, 20, 3). Aby podać wyznaczony ciąg, powinna wywołać: send(7) Page 2 of 5
send(3) send(2) send(70) send(15) send(20) send(3) Załóżmy teraz, że wszystkie papugi doleciały do celu, a otrzymany ciąg liczb to (3, 20, 70, 15, 2, 3, 7). Procedura decode zostanie wówczas wywołana z parametrami N=3, L=7 oraz X= 3 20 70 15 2 3 7 Procedura decode musi odtworzyć oryginalną wiadomość (10, 30, 20). Powinna ona podać odpowiedź przez wywołanie output(10) output(30) output(20) Podzadania Podzadanie 1. (17 punktów) N = 8, a każda liczba w tablicy M to 0 lub 1. Każda zakodowana liczba musi mieścić się w przedziale od 0 do R=65535. Podzadanie 2. (17 punktów) 1 N 16. Każda zakodowana liczba musi mieścić się w przedziale od 0 do R=65535. Podzadanie 3. (18 punktów) 1 N 16. Page 3 of 5
Podzadanie 4. (29 punktów) 1 N 32. Podzadanie 5. (do 19 punktów) 16 N 64. Maksymalna dopuszczalna liczba wywołań procedury send wynosi K=15 N. Ważne: wynik za to zadanie zależy od ilorazu między długością zakodowanej wiadomości a długością oryginalnej wiadomości. Dla danego testu t w tym podzadaniu niech Pt=Lt/Nt oznacza iloraz między długością zakodowanej wiadomości Lt a długością oryginalnej wiadomości Nt. Niech P będzie największą spośród wszystkich wartości Pt. Twój wynik w tym podzadaniu zostanie okreśony na podstawie następujących zasad: Jeśli P 5, otrzymasz 19 punktów. Jeśli 5 < P 6, otrzymasz 18 punktów. Jeśli 6 < P 7, otrzymasz 17 punktów. Jeśli 7 < P 15, otrzymasz 1 + 2 (15 - P) punktów (zaokrąglone w dół). Jeśli P > 15 lub dowolna z odpowiedzi jest niepoprawna, otrzymasz 0 punktów. Ważne: Każde poprawne rozwiązanie podzadań od 1 do 4 jest w stanie rozwiązać poprzednie podzadania. Jednakże, z powodu większego ograniczenia na K, poprawne rozwiązanie podzadania 5 może nie być dobre dla podzadań od 1 do 4. Istnieje rozwiązanie, które rozwiązuje wszystkie podzadania tą samą metodą. Szczegóły techniczne Ograniczenia i uwagi Podczas oceny, Twoje zgłoszenia zostaną skompilowane do dwóch programów e oraz d, które zostaną uruchomione osobno. Obydwie napisane przez Ciebie procedury zostaną włączone w każdy program (tj. zlinkowane), lecz tylko e będzie wywoływać procedurę encode, a tylko d będzie wykonywać decode. Limit czasu procesora: Program e wywoła procedurę encode 50 razy i musi działać co najwyżej 2 sekundy. Podobnie, program d wywoła procedurę decode 50 razy i powinien działać co najwyżej 2 sekundy. Dostępna pamięć: 256 MB Uwaga: Nie ma osobnego ograniczenia na rozmiar stosu. Pamięć użyta przez stos wlicza się w całkowity rozmiar używanej pamięci. Page 4 of 5
Interfejs (API) Katalog na pliki źródłowe: parrots/ Nazwa plików z rozwiązaniami: encoder.c lub encoder.cpp lub encoder.pas decoder.c lub decoder.cpp lub decoder.pas Uwaga dla fanów C/C++: zarówno w przykładowym, jak i ostatecznym module oceniającym, pliki encoder.c[pp] i decoder.c[pp] zostaną ze sobą zlinkowane. Aby zapobiec konfliktom zmiennych globalnych w różnych plikach, możesz poprzedzić ich deklaracje modyfikatorem static. Interfejs procedur zawodnika: encoder.h lub encoder.pas decoder.h lub decoder.pas Interfejs procedur modułu oceniającego: encoderlib.h lub encoderlib.pas decoderlib.h lub decoderlib.pas Przykładowy moduł oceniający: grader.c lub grader.cpp lub grader.pas Przykładowy moduł oceniający wykonuje dwie osobne rundy. W każdej rundzie wywołuje najpierw procedurę encode z podanymi danymi, a następnie procedurę decode, podając jej wynik wyznaczony przez procedurę encode. W pierwszej rundzie, moduł oceniający nie zmienia kolejności wiadomości w zakodowanej wiadomości. W drugiej rundzie, moduł zamienia liczby na pozycjach parzystych i nieparzystych. Prawdziwy moduł oceniający będzie tasować zakodowane wiadomości na różne sposoby. Możesz zmienić sposób tasowania w przykładowym module oceniającym przez modyfikację procedury shuffle (w C/C++) lub Shuffle (w Pascalu). Przykładowy moduł oceniający sprawdza również zakres oraz długość zakodowanych danych. Domyślnie sprawdza on, czy zakodowane dane mieszczą się w przedziale od 0 do 65535 i czy długość nie przekracza 10 N. Możesz to zmienić przez zmianę wartości stałych channel_range (na przykład z 65535 na 255) oraz max_expansion (na przykład z 10 na 15 lub 7). Pliki wejściowe dla przykładowego modułu oceniającego: grader.in.1, grader.in.2,... Uwaga: Przykładowy moduł oceniający wczytuje dane zgodnie z poniższym formatem: Wiersz 1: N Wiersz 2: lista N liczb całkowitych: M[0], M[1],..., M[N-1] Pliki z oczekiwaną odpowiedzią dla przykładowych wejść przykładowego modułu oceniającego: grader.expect.1, grader.expect.2,... W tym zadaniu powyższe pliki powinny zawierać jedynie napis Correct. Page 5 of 5