Informatyczny kącik olimpijski
Sklep ze słodyczami
Tym razem zadanie Candies z Bałtyckiej Olimpiady Informatycznej z 2010 roku.
Zadanie. W sklepie znajduje się paczek z cukierkami, -ta z nich zawiera cukierków. Sklepikarz może sprzedawać jedynie całe paczki, więc jeśli w sklepie są cztery paczki zawierające 1, 3, 4 i 4 cukierki, to może on obsłużyć następnego klienta tylko wtedy, gdy ten złoży zamówienie jednego z 9 rozmiarów (konkretnie gdy poprosi o 1, 3, 4, 5, 7, 8, 9, 11 lub 12 cukierków). Sklepikarz zastanawia się, jak bardzo mógłby zwiększyć liczbę możliwości, gdyby zamienił liczbę cukierków w jednej z paczek. Przykładowo, po wyrzuceniu jednej paczki z 4 cukierkami i dodaniu paczki z 9 cukierkami, liczba możliwych do zrealizowania zamówień zwiększy się do 13 (będą to 1, 3, 4, 5, 7, 8, 9, 10, 12, 13, 14, 16, 17). Jeśli istnieje więcej niż jedno optymalne rozwiązanie, w którym sklepikarz zamienia paczkę z cukierkami na paczkę z cukierkami, należy podać to, w którym para jest minimalna leksykograficznie.
Załóżmy na początek, że wyrzuciliśmy którąś z paczek, a zestaw pozostałych paczek umożliwia zrealizowanie zamówień o wielkościach (zakładamy przy tym, że zamówienie również jest poprawne). Jeśli dodamy do tego zestawu paczkę cukierków, to będziemy mogli dodatkowo zrealizować zamówienia a zatem jeśli nie jest równe żadnej różnicy to liczba zamówień wzrośnie dwukrotnie. Możemy to sobie zagwarantować, dodając wystarczająco dużą paczkę, np. rozmiaru Rozwiązanie zadania można zatem podzielić na dwie części: znalezienie paczki której wyrzucenie jak najmniej zmniejszy liczbę możliwych zamówień, oraz znalezienie jak najmniejszej paczki która spowoduje dwukrotne zwiększenie liczby możliwych zamówień.
Zadanie to jest pewną wariacją na temat problemu plecakowego (o którym pisaliśmy m.in. w numerze 6/2013). W szczególności wyznaczenie liczby zamówień możliwych do zrealizowania przez początkowy zestaw paczek to zastosowanie tego algorytmu do przedmiotów rozmiarów i plecaka o udźwigu
Pseudokod algorytmu znajduje się obok. Przypomnijmy istotne dla nas kwestie: czas działania algorytmu wynosi analizuje on przedmioty pojedynczo (w czasie każdy), aktualizując tablicę (w wynikowej tablicy mamy jeśli zamówienie rozmiaru może być zrealizowane), oraz dla ostatecznego wyniku nie ma znaczenia kolejność, w której przedmioty są analizowane. Możemy abstrahować od szczegółów implementacyjnych i zamknąć go w strukturze danych, która w czasie będzie umożliwiała wykonywanie trzech operacji: zrobienie kopii struktury, dodanie nowego przedmiotu oraz wyznaczenie liczby zamówień realizowanych przez dodane przedmioty.
Aby znaleźć paczkę potrzebujemy rozwiązać problem plecakowy dla każdego podzbioru przedmiotów. Jeśli rozpatrzymy każdy z tych podzbiorów niezależnie, dostaniemy algorytm o złożoności czasowej
Możemy postąpić nieco sprytniej. Będziemy utrzymywać listę struktur danych (na początek zaczynamy z jedną pustą strukturą danych). Teraz, dopóki struktury na liście zawierają mniej niż przedmiotów, to dla każdej struktury dzielimy zbiór przedmiotów niewystępujących w tej strukturze na dwa w miarę równe podzbiory i a strukturę zastępujemy jej kopiami i do których dodajemy przedmioty odpowiednio z podzbiorów i (patrz rysunek). Jeśli dla uproszczenia założymy, że jest potęgą dwójki, to w -tej fazie tego algorytmu wygenerujemy struktur, do każdej z nich dodając przedmiotów. Zatem złożoność czasowa każdej z faz wyniesie czyli rozwiązanie problemu plecakowego dla wszystkich podzbiorów przedmiotów zajmie czas
Pozostaje teraz znalezienie minimalnej liczby która nie będzie równa żadnej różnicy Ponieważ są zamówieniami generowanymi przez wybrany podzbiór paczek, to wszystkie różnice będą generowane przez zbiór Wystarczy zatem rozwiązać problem plecakowy dla takich przedmiotów (w naszej wersji tego problemu przedmioty o ujemnym rozmiarze nie stanowią problemu, należy jednak zwrócić uwagę na rozmiar tablicy i poprawną kolejność pętli) i zwrócić jako minimalną dodatnią liczbę, dla której Czas działania tej części rozwiązania to