Komentarz Pieniądze wielkie pieniądze
Pieniądze wielkie pieniądze Jak donosi prasa branżowa, w pierwszym dniu po wdrożeniu nowego systemu bankomatów, akcje Kupakasi Bank na nowojorskiej giełdzie zyskały 30%. Problemy z dotychczasowym oprogramowaniem powodowały spory odpływ klientów, zaś utracona przez wszystkich wiara w terminowe i bezawaryjne wdrożenie podkopała zaufanie do Banku jeszcze bardziej. Ku zaskoczeniu wszystkich, system zadziałał bezbłędnie, zaś najbardziej ryzykowny element obliczający jakimi nominałami bankomat ma wypłacić żądaną kwotę przeszedł szybko testy akceptacyjne i działa z powodzeniem w warunkach produkcyjnych. Kupakasi Bank z optymizmem patrzy w przyszłość, zarząd jest wniebowzięty a prezes Tukosi-Takasa za otrzymaną premię już zamówił dwutygodniowe wczasy na Bora-Bora. Co było do zrobienia W literaturze informatycznej znany jest problem wydawania reszty. W klasycznym ujęciu polega on na obliczeniu, jak wydać resztę przy użyciu jak najmniejszej liczby monet przy danych nominałach, jakimi dysponuje sprzedawca. Nasz problem, jest pokrewny, jednak nieco się różni. Oprócz różnic czysto kosmetycznych, takich jak wypłata banknotów a nie monet przez bankomat a nie sprzedawcę nieco zmodyfikowaliśmy oryginalny problem. Nie nałożyliśmy ograniczenia na optymalizację liczby banknotów, jednak oprócz nominałów, dostaliście również informację o liczbie banknotów z każdego nominału, jakimi dysponuje bankomat. Zadaniem Waszym było napisanie kodu do jasno sprecyzowanego API, który realizuje problem wypłaty gotówki z bankomatu i obliczania w jakich banknotach należy wypłacić żądaną kwotę. Dodatkowym wyzwaniem, było należyte obsłużenie sytuacji, gdy wypłata nie jest możliwa i zasugerowanie mniejszej jak i większej kwoty, przy której pieniądze będzie można wypłacić.
Rozwiązanie Przy rozwiązaniu zadania można skorzystać ze znanych sposobów rozwiązania problemu wydawania reszty. Jednym z nich jest algorytm zachłanny. Jego praca jest iteracyjna, zaś każda iteracja polega na odejmowaniu od żądanej kwoty wypłaty największego dostępnego nominału mniejszego od pozostałej kwoty (po odjęciu we wcześniejszych iteracjach). Odejmowana kwota reprezentuje wypłacany nominał. Iteracje powtarza się do momentu uzyskania wyniku 0 lub stwierdzenia, że nie da się takiego uzyskać. Wadą tego algorytmu w opisanej postaci bywa nieskuteczność. Np. nie zadziała gdy mamy dostępne nominały 20 i 50 (pomijając dla uproszczenia zasoby bankomatu) zaś żądana kwota wypłaty to 110. Algorytm zaproponuje wypłatę 2 razy po 50 i gdy zostanie 10 stwierdzi, że dalsza wypłata jest niemożliwa. Tymczasem można jak najbardziej żądaną kwotę wypłacić w nominałach 20, 20, 20 i 50. Dlatego by uzyskać maksymalną skuteczność algorytmu, mówiąc kolokwialnie, po dojściu do wniosku, że wypłata jest niemożliwa, należałoby cofnąć ostatnią wypłatę i spróbować mniejszymi nominałami. I próbować w ten sposób do skutku. Pozostawiamy czytelnikom analizę innego podejścia opartego o programowanie dynamiczne, które naszym zdaniem jest rozwiązaniem bardziej preferowanym. Jak ocenialiśmy Poprawna implementacja ilości zwracanych banknotów do 150 punktów Poprawna implementacja sugerowanych kwot wypłaty, w przypadku braku możliwości zrealizowania pierwotnej wypłaty do 150 punktów EXTRA bonus za rzeczy które nas pozytywnie zaskoczą do 150 punktów, w tym o Testy jednostkowe ( do 50 punktów) o Osiągnięcie najniższej złożoności obliczeniowej wśród wszystkich uczestników (50 punktów) o Premia za wyjątkowo dobrą jakość kodu (do 50 punktów) Maksymalna ilość punktów do uzyskania w zadaniu: 450 pkt.
Jak poszło Liczyliśmy na to, że zadanie będzie momentem złapania oddechu przed finiszem i wielkim finałem. Lekka zabawa algorytmiczna, bez wygórowanych wymagań miała zapewnić dobrą zabawę. Jednak biorąc pod uwagę liczbę nadesłanych prac oraz pewne dostrzeżone problemy, odnieśliśmy wrażenie, że jednak zadanie nie było wcale takie proste. Bez wątpienia przyczynił się do tego również wielkanocny nastrój. Niestety harmonogram konkursu jest nieubłagany. Najmniej problemu sprawiło zwrócenie informacji o tym, że wypłata jest niemożliwa. Względnie dobrze oceniliśmy również zwrócenie informacji o nominałach wypłaty. Więcej problemów przysporzyło sugerowane kwoty wypłaty, przy czym znacznie lepiej radziliście sobie z zasugerowaniem kwot wypłaty, gdy wypłata była niemożliwa ze względu na brak odpowiednich nominałów w bankomacie, gorzej zaś, gdy wynikała ona z niedostatecznych zasobów bankomatu. Z nieukrywanym zadowoleniem odnotowujemy ogromny wzrost liczby prac, zawierających testy. Oczywiście tym razem zmotywowaliśmy Was do tego punktacją, mamy jednak nadzieję, że Wasze prace odniosły korzyść z ich napisania. Jesteśmy bardzo ciekawi, czy pokusiliście się o wykorzystywanie w swojej pracy również praktyk Test-Driven Development. W każdym razie gorąco do tego zachęcamy. Statystyki Nadesłanych odpowiedzi 12 Najwięcej uzyskanych punktów 410 Najmniej uzyskanych punktów 0 Suma punktów 3200 Średnia arytmetyczna 267 W zależności od języka programowania: Java 4 C++ 4 Najmniej uzyskanych punktów 4 W zależności od zawartości: Prace posiadające testy 11 Prace obliczające w pełni poprawnie kwotę wypłaty 7 Prace poprawnie informujące o braku możliwości wypłaty 9 Prace obliczające w pełni poprawnie sugestie wypłaty 4
Ciekawostki Znaleźliśmy prace, w których pomimo ewidentnych różnic implementacyjnych popełniono te same błędy przy sugerowaniu kwot wypłaty. Oględziny nie doprowadziły nas do wniosku, że to praca wspólna, jednak zbieżność toku myślenia zadziwia W API Javy został znaleziony przez uczestników niezamierzony błąd. Getter Nie wszyscy z Was odkryli możliwość stosowania tzw. mock objectów, jako bardzo pożytecznej techniki pozwalającej na efektywne pisanie testów jednostkowych klas posiadających zależności.